from typing import List, Dict, Any
import networkx as nx
from .pump_protocol import generate_pump_protocol


def get_vessel_liquid_volume(G: nx.DiGraph, vessel: str) -> float:
    """
    获取容器中的液体体积
    """
    if vessel not in G.nodes():
        return 0.0
    
    vessel_data = G.nodes[vessel].get('data', {})
    liquids = vessel_data.get('liquid', [])
    
    total_volume = 0.0
    for liquid in liquids:
        if isinstance(liquid, dict) and 'liquid_volume' in liquid:
            total_volume += liquid['liquid_volume']
    
    return total_volume


def find_centrifuge_device(G: nx.DiGraph) -> str:
    """
    查找离心机设备
    """
    centrifuge_nodes = [node for node in G.nodes() 
                       if (G.nodes[node].get('class') or '') == 'virtual_centrifuge']
    
    if centrifuge_nodes:
        return centrifuge_nodes[0]
    
    raise ValueError("系统中未找到离心机设备")


def find_centrifuge_vessel(G: nx.DiGraph) -> str:
    """
    查找离心机专用容器
    """
    possible_names = [
        "centrifuge_tube",
        "centrifuge_vessel", 
        "tube_centrifuge",
        "vessel_centrifuge",
        "centrifuge",
        "tube_15ml",
        "tube_50ml"
    ]
    
    for vessel_name in possible_names:
        if vessel_name in G.nodes():
            return vessel_name
    
    raise ValueError(f"未找到离心机容器。尝试了以下名称: {possible_names}")


def generate_centrifuge_protocol(
    G: nx.DiGraph,
    vessel: str,
    speed: float,
    time: float,
    temp: float = 25.0
) -> List[Dict[str, Any]]:
    """
    生成离心操作的协议序列，复用 pump_protocol 的成熟算法
    
    离心流程：
    1. 液体转移：将待离心溶液从源容器转移到离心机容器
    2. 离心操作：执行离心分离
    3. 上清液转移：将离心后的上清液转移回原容器或新容器
    4. 沉淀处理：处理离心沉淀（可选）
    
    Args:
        G: 有向图，节点为设备和容器，边为流体管道
        vessel: 包含待离心溶液的容器名称
        speed: 离心速度 (rpm)
        time: 离心时间 (秒)
        temp: 离心温度 (°C)，默认25°C
    
    Returns:
        List[Dict[str, Any]]: 离心操作的动作序列
    
    Raises:
        ValueError: 当找不到必要的设备时抛出异常
    
    Examples:
        centrifuge_actions = generate_centrifuge_protocol(G, "reaction_mixture", 5000, 600, 4.0)
    """
    action_sequence = []
    
    print(f"CENTRIFUGE: 开始生成离心协议")
    print(f"  - 源容器: {vessel}")
    print(f"  - 离心速度: {speed} rpm")
    print(f"  - 离心时间: {time}s ({time/60:.1f}分钟)")
    print(f"  - 离心温度: {temp}°C")
    
    # 验证源容器存在
    if vessel not in G.nodes():
        raise ValueError(f"源容器 '{vessel}' 不存在于系统中")
    
    # 获取源容器中的液体体积
    source_volume = get_vessel_liquid_volume(G, vessel)
    print(f"CENTRIFUGE: 源容器 {vessel} 中有 {source_volume} mL 液体")
    
    # 查找离心机设备
    try:
        centrifuge_id = find_centrifuge_device(G)
        print(f"CENTRIFUGE: 找到离心机: {centrifuge_id}")
    except ValueError as e:
        raise ValueError(f"无法找到离心机: {str(e)}")
    
    # 查找离心机容器
    try:
        centrifuge_vessel = find_centrifuge_vessel(G)
        print(f"CENTRIFUGE: 找到离心机容器: {centrifuge_vessel}")
    except ValueError as e:
        raise ValueError(f"无法找到离心机容器: {str(e)}")
    
    # === 简化的体积计算策略 ===
    if source_volume > 0:
        # 如果能检测到液体体积，使用实际体积的大部分
        transfer_volume = min(source_volume * 0.9, 15.0)  # 90%或最多15mL（离心管通常较小）
        print(f"CENTRIFUGE: 检测到液体体积，将转移 {transfer_volume} mL")
    else:
        # 如果检测不到液体体积，默认转移标准量
        transfer_volume = 10.0  # 标准离心管体积
        print(f"CENTRIFUGE: 未检测到液体体积，默认转移 {transfer_volume} mL")
    
    # === 第一步：将待离心溶液转移到离心机容器 ===
    print(f"CENTRIFUGE: 将 {transfer_volume} mL 溶液从 {vessel} 转移到 {centrifuge_vessel}")
    try:
        # 使用成熟的 pump_protocol 算法进行液体转移
        transfer_to_centrifuge_actions = generate_pump_protocol(
            G=G,
            from_vessel=vessel,
            to_vessel=centrifuge_vessel,
            volume=transfer_volume,
            flowrate=1.0,  # 离心转移用慢速，避免气泡
            transfer_flowrate=1.0
        )
        action_sequence.extend(transfer_to_centrifuge_actions)
    except Exception as e:
        raise ValueError(f"无法将溶液转移到离心机: {str(e)}")
    
    # 转移后等待
    wait_action = {
        "action_name": "wait",
        "action_kwargs": {"time": 5}
    }
    action_sequence.append(wait_action)
    
    # === 第二步：执行离心操作 ===
    print(f"CENTRIFUGE: 执行离心操作")
    centrifuge_action = {
        "device_id": centrifuge_id,
        "action_name": "centrifuge",
        "action_kwargs": {
            "vessel": centrifuge_vessel,
            "speed": speed,
            "time": time,
            "temp": temp
        }
    }
    action_sequence.append(centrifuge_action)
    
    # 离心后等待系统稳定
    wait_action = {
        "action_name": "wait",
        "action_kwargs": {"time": 10}  # 离心后等待稍长，让沉淀稳定
    }
    action_sequence.append(wait_action)
    
    # === 第三步：将上清液转移回原容器 ===
    print(f"CENTRIFUGE: 将上清液从离心机转移回 {vessel}")
    try:
        # 估算上清液体积（约为转移体积的80% - 假设20%成为沉淀）
        supernatant_volume = transfer_volume * 0.8
        print(f"CENTRIFUGE: 预计上清液体积 {supernatant_volume} mL")
        
        transfer_back_actions = generate_pump_protocol(
            G=G,
            from_vessel=centrifuge_vessel,
            to_vessel=vessel,
            volume=supernatant_volume,
            flowrate=0.5,  # 上清液转移更慢，避免扰动沉淀
            transfer_flowrate=0.5
        )
        action_sequence.extend(transfer_back_actions)
    except Exception as e:
        print(f"CENTRIFUGE: 将上清液转移回容器失败: {str(e)}")
    
    # === 第四步：清洗离心机容器 ===
    print(f"CENTRIFUGE: 清洗离心机容器")
    try:
        # 查找清洗溶剂
        cleaning_solvent = None
        for solvent in ["flask_water", "flask_ethanol", "flask_acetone"]:
            if solvent in G.nodes():
                cleaning_solvent = solvent
                break
        
        if cleaning_solvent:
            # 用少量溶剂清洗离心管
            cleaning_volume = 5.0  # 5mL清洗
            print(f"CENTRIFUGE: 用 {cleaning_volume} mL {cleaning_solvent} 清洗")
            
            # 清洗溶剂加入
            cleaning_actions = generate_pump_protocol(
                G=G,
                from_vessel=cleaning_solvent,
                to_vessel=centrifuge_vessel,
                volume=cleaning_volume,
                flowrate=2.0,
                transfer_flowrate=2.0
            )
            action_sequence.extend(cleaning_actions)
            
            # 将清洗液转移到废液
            if "waste_workup" in G.nodes():
                waste_actions = generate_pump_protocol(
                    G=G,
                    from_vessel=centrifuge_vessel,
                    to_vessel="waste_workup",
                    volume=cleaning_volume,
                    flowrate=2.0,
                    transfer_flowrate=2.0
                )
                action_sequence.extend(waste_actions)
        
    except Exception as e:
        print(f"CENTRIFUGE: 清洗步骤失败: {str(e)}")
    
    print(f"CENTRIFUGE: 生成了 {len(action_sequence)} 个动作")
    print(f"CENTRIFUGE: 离心协议生成完成")
    print(f"CENTRIFUGE: 总处理体积: {transfer_volume} mL")
    
    return action_sequence


# 便捷函数：常用离心方案
def generate_low_speed_centrifuge_protocol(
    G: nx.DiGraph,
    vessel: str,
    time: float = 300.0  # 5分钟
) -> List[Dict[str, Any]]:
    """低速离心：细胞分离或大颗粒沉淀"""
    return generate_centrifuge_protocol(G, vessel, 1000.0, time, 4.0)


def generate_high_speed_centrifuge_protocol(
    G: nx.DiGraph,
    vessel: str,
    time: float = 600.0  # 10分钟
) -> List[Dict[str, Any]]:
    """高速离心：蛋白质沉淀或小颗粒分离"""
    return generate_centrifuge_protocol(G, vessel, 12000.0, time, 4.0)


def generate_standard_centrifuge_protocol(
    G: nx.DiGraph,
    vessel: str,
    time: float = 600.0  # 10分钟
) -> List[Dict[str, Any]]:
    """标准离心：常规样品处理"""
    return generate_centrifuge_protocol(G, vessel, 5000.0, time, 25.0)


def generate_cold_centrifuge_protocol(
    G: nx.DiGraph,
    vessel: str,
    speed: float = 5000.0,
    time: float = 600.0
) -> List[Dict[str, Any]]:
    """冷冻离心：热敏感样品处理"""
    return generate_centrifuge_protocol(G, vessel, speed, time, 4.0)


def generate_ultra_centrifuge_protocol(
    G: nx.DiGraph,
    vessel: str,
    time: float = 1800.0  # 30分钟
) -> List[Dict[str, Any]]:
    """超高速离心：超细颗粒分离"""
    return generate_centrifuge_protocol(G, vessel, 15000.0, time, 4.0)