"""
Streamlit 配方优化交互界面

启动应用:
    streamlit run app/app.py

Docker 环境变量:
    API_URL: API 服务地址 (默认: http://localhost:8000)
"""

import io
import os
from datetime import datetime

import httpx
import pandas as pd
import streamlit as st

# ============ 配置 ============

# 从环境变量读取 API 地址，支持 Docker 环境
API_URL = os.environ.get("API_URL", "http://localhost:8000")

AVAILABLE_ORGANS = [
    "liver",
    "spleen", 
    "lung",
    "heart",
    "kidney",
    "muscle",
    "lymph_nodes",
]

ORGAN_LABELS = {
    "liver": "肝脏 (Liver)",
    "spleen": "脾脏 (Spleen)",
    "lung": "肺 (Lung)",
    "heart": "心脏 (Heart)",
    "kidney": "肾脏 (Kidney)",
    "muscle": "肌肉 (Muscle)",
    "lymph_nodes": "淋巴结 (Lymph Nodes)",
}

AVAILABLE_ROUTES = [
    "intravenous",
    "intramuscular",
]

ROUTE_LABELS = {
    "intravenous": "静脉注射 (Intravenous)",
    "intramuscular": "肌肉注射 (Intramuscular)",
}

# ============ 页面配置 ============

st.set_page_config(
    page_title="LNP 配方优化",
    page_icon="🧬",
    layout="wide",
    initial_sidebar_state="expanded",
)

# ============ 自定义样式 ============

st.markdown("""
<style>
    /* 主标题样式 */
    .main-title {
        font-size: 2.5rem;
        font-weight: 700;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        text-align: center;
        margin-bottom: 0.5rem;
    }
    
    /* 副标题样式 */
    .sub-title {
        font-size: 1.1rem;
        color: #6c757d;
        text-align: center;
        margin-bottom: 2rem;
    }
    
    /* 结果卡片 */
    .result-card {
        background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
        border-radius: 12px;
        padding: 1.5rem;
        margin-bottom: 1rem;
    }
    
    /* 指标高亮 */
    .metric-highlight {
        font-size: 2rem;
        font-weight: 700;
        color: #667eea;
    }
    
    /* 侧边栏样式 */
    .sidebar-section {
        background: #f8f9fa;
        border-radius: 8px;
        padding: 1rem;
        margin-bottom: 1rem;
    }
    
    /* 状态指示器 */
    .status-online {
        color: #28a745;
        font-weight: 600;
    }
    
    .status-offline {
        color: #dc3545;
        font-weight: 600;
    }
    
    /* 表格样式优化 */
    .dataframe {
        font-size: 0.85rem;
    }
</style>
""", unsafe_allow_html=True)


# ============ 辅助函数 ============

def check_api_status() -> bool:
    """检查 API 状态"""
    try:
        with httpx.Client(timeout=5) as client:
            response = client.get(f"{API_URL}/")
            return response.status_code == 200
    except:
        return False


def call_optimize_api(
    smiles: str,
    organ: str,
    top_k: int = 20,
    num_seeds: int = None,
    top_per_seed: int = 1,
    step_sizes: list = None,
    wr_step_sizes: list = None,
    comp_ranges: dict = None,
    routes: list = None,
    scoring_weights: dict = None,
) -> dict:
    """调用优化 API"""
    payload = {
        "smiles": smiles,
        "organ": organ,
        "top_k": top_k,
        "num_seeds": num_seeds,
        "top_per_seed": top_per_seed,
        "step_sizes": step_sizes,
        "wr_step_sizes": wr_step_sizes,
        "comp_ranges": comp_ranges,
        "routes": routes,
        "scoring_weights": scoring_weights,
    }
    
    with httpx.Client(timeout=600) as client:  # 10 分钟超时（自定义参数可能需要更长时间）
        response = client.post(
            f"{API_URL}/optimize",
            json=payload,
        )
        response.raise_for_status()
        return response.json()


# PDI 分类标签
PDI_CLASS_LABELS = {
    0: "<0.2 (优)",
    1: "0.2-0.3 (良)",
    2: "0.3-0.4 (中)",
    3: ">0.4 (差)",
}

# EE 分类标签
EE_CLASS_LABELS = {
    0: "<50% (低)",
    1: "50-80% (中)",
    2: ">80% (高)",
}

# 毒性分类标签
TOXIC_CLASS_LABELS = {
    0: "无毒 ✓",
    1: "有毒 ⚠",
}


def format_results_dataframe(results: dict, smiles_label: str = None) -> pd.DataFrame:
    """将 API 结果转换为 DataFrame"""
    formulations = results["formulations"]
    target_organ = results["target_organ"]
    
    rows = []
    for f in formulations:
        row = {}
        
        # 如果有 SMILES 标签，添加到首列
        if smiles_label:
            row["SMILES"] = smiles_label
        
        row.update({
            "排名": f["rank"],
        })
        # 如果有综合评分，显示在排名后面
        if f.get("composite_score") is not None:
            row["综合评分"] = f"{f['composite_score']:.4f}"
        row.update({
            f"{target_organ}分布": f"{f['target_biodist']*100:.8f}%",
            "阳离子脂质/mRNA比例": f["cationic_lipid_to_mrna_ratio"],
            "阳离子脂质(mol)比例": f["cationic_lipid_mol_ratio"],
            "磷脂(mol)比例": f["phospholipid_mol_ratio"],
            "胆固醇(mol)比例": f["cholesterol_mol_ratio"],
            "PEG脂质(mol)比例": f["peg_lipid_mol_ratio"],
            "辅助脂质": f["helper_lipid"],
            "给药途径": f["route"],
        })
        
        # 添加额外预测值
        if f.get("quantified_delivery") is not None:
            row["量化递送"] = f"{f['quantified_delivery']:.4f}"
        if f.get("unnormalized_delivery") is not None:
            row["总荧光强度"] = f"{f['unnormalized_delivery']:.4f}"
        if f.get("size") is not None:
            row["粒径(nm)"] = f"{f['size']:.1f}"
        if f.get("pdi_class") is not None:
            row["PDI"] = PDI_CLASS_LABELS.get(f["pdi_class"], str(f["pdi_class"]))
        if f.get("ee_class") is not None:
            row["包封率"] = EE_CLASS_LABELS.get(f["ee_class"], str(f["ee_class"]))
        if f.get("toxic_class") is not None:
            row["毒性"] = TOXIC_CLASS_LABELS.get(f["toxic_class"], str(f["toxic_class"]))
        
        # 添加其他器官的 biodist
        for organ, value in f["all_biodist"].items():
            if organ != target_organ:
                row[f"{organ}分布"] = f"{value*100:.2f}%"
        rows.append(row)
    
    return pd.DataFrame(rows)


def create_export_csv(df: pd.DataFrame, smiles: str, organ: str) -> str:
    """创建导出用的 CSV 内容"""
    # 添加元信息
    meta_info = f"# LNP 配方优化结果\n# SMILES: {smiles}\n# 目标器官: {organ}\n# 导出时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
    csv_content = df.to_csv(index=False)
    return meta_info + csv_content


# ============ 主界面 ============

def main():
    # 标题
    st.markdown('<h1 class="main-title">🧬 LNP 配方优化系统</h1>', unsafe_allow_html=True)
    st.markdown('<p class="sub-title">基于深度学习的脂质纳米颗粒配方智能优选</p>', unsafe_allow_html=True)
    
    # 检查 API 状态
    api_online = check_api_status()
    
    # ========== 侧边栏 ==========
    with st.sidebar:
        # st.header("⚙️ 参数设置")
        
        # API 状态
        if api_online:
            st.success("🟢 API 服务在线")
        else:
            st.error("🔴 API 服务离线")
            st.info("请先启动 API 服务:\n```\nuvicorn app.api:app --port 8000\n```")
        
        # st.divider()
        
        # SMILES 输入
        st.subheader("🔬 分子结构")
        smiles_input = st.text_area(
            "输入阳离子脂质 SMILES",
            value="",
            height=100,
            placeholder="例如: CC(C)NCCNC(C)C\n多条SMILES用英文逗号分隔: SMI1,SMI2,SMI3",
            help="输入阳离子脂质的 SMILES 字符串。支持多条 SMILES，用英文逗号 (,) 分隔",
        )
        
        # 示例 SMILES
        # with st.expander("📋 示例 SMILES"):
        #     example_smiles = {
        #         "DLin-MC3-DMA": "CC(C)=CCCC(C)=CCCC(C)=CCN(C)CCCCCCCCOC(=O)CCCCCCC/C=C\\CCCCCCCC",
        #         "简单胺": "CC(C)NCCNC(C)C",
        #         "长链胺": "CCCCCCCCCCCCNCCNCCCCCCCCCCCC",
        #     }
        #     for name, smi in example_smiles.items():
        #         if st.button(f"使用 {name}", key=f"example_{name}"):
        #             st.session_state["smiles_input"] = smi
        #             st.rerun()
        
        # st.divider()
        
        # 目标器官选择
        st.subheader("🎯 目标器官")
        selected_organ = st.selectbox(
            "选择优化目标器官",
            options=AVAILABLE_ORGANS,
            format_func=lambda x: ORGAN_LABELS.get(x, x),
            index=0,
        )
        
        # 给药途径选择
        st.subheader("💉 给药途径")
        selected_routes = st.multiselect(
            "选择给药途径",
            options=AVAILABLE_ROUTES,
            default=AVAILABLE_ROUTES,
            format_func=lambda x: ROUTE_LABELS.get(x, x),
            help="选择要搜索的给药途径，可多选。至少选择一种。",
        )
        if not selected_routes:
            st.warning("⚠️ 请至少选择一种给药途径")
        
        # 高级选项
        with st.expander("🔧 高级选项"):
            st.markdown("**输出设置**")
            top_k = st.slider(
                "返回配方数量 (top_k)",
                min_value=5,
                max_value=100,
                value=20,
                step=5,
                help="最终返回的最优配方数量",
            )
            
            st.markdown("**搜索策略**")
            num_seeds = st.slider(
                "种子点数量 (num_seeds)",
                min_value=10,
                max_value=200,
                value=top_k * 5,
                step=10,
                help="第一轮迭代后保留的种子点数量，更多种子点意味着更广泛的搜索",
            )
            
            top_per_seed = st.slider(
                "每个种子的局部最优数 (top_per_seed)",
                min_value=1,
                max_value=5,
                value=1,
                step=1,
                help="后续迭代中，每个种子点邻域保留的局部最优数量",
            )
            
            st.markdown("**迭代步长与轮数**")
            use_custom_steps = st.checkbox(
                "自定义迭代步长",
                value=False,
                help="默认 mol ratio 步长 [10, 2, 1]（百分数），weight ratio 步长 [5, 2, 1]，共3轮。将某轮步长设为0可减少迭代轮数。",
            )
            
            if use_custom_steps:
                st.caption("**Mol ratio 步长 (%)**")
                col1, col2, col3 = st.columns(3)
                with col1:
                    step1 = st.number_input(
                        "第1轮 mol 步长",
                        min_value=1, max_value=20, value=10,
                        step=1,
                        help="第1轮为全局粗搜索",
                        key="mol_step1",
                    )
                with col2:
                    step2 = st.number_input(
                        "第2轮 mol 步长",
                        min_value=0, max_value=10, value=2,
                        step=1,
                        help="设为0则只进行1轮搜索",
                        key="mol_step2",
                    )
                with col3:
                    step3 = st.number_input(
                        "第3轮 mol 步长",
                        min_value=0, max_value=5, value=1,
                        step=1,
                        help="设为0则只进行2轮搜索",
                        key="mol_step3",
                    )
                
                st.caption("**Weight ratio 步长**")
                col1, col2, col3 = st.columns(3)
                with col1:
                    wr_step1 = st.number_input(
                        "第1轮 WR 步长",
                        min_value=1.0, max_value=10.0, value=5.0,
                        step=1.0, format="%.1f",
                        key="wr_step1",
                    )
                with col2:
                    wr_step2 = st.number_input(
                        "第2轮 WR 步长",
                        min_value=0.0, max_value=5.0, value=2.0,
                        step=0.5, format="%.1f",
                        key="wr_step2",
                    )
                with col3:
                    wr_step3 = st.number_input(
                        "第3轮 WR 步长",
                        min_value=0.0, max_value=2.0, value=1.0,
                        step=0.5, format="%.1f",
                        key="wr_step3",
                    )
                
                if step2 == 0:
                    step_sizes = [float(step1)]
                    wr_step_sizes_val = [wr_step1]
                elif step3 == 0:
                    step_sizes = [float(step1), float(step2)]
                    wr_step_sizes_val = [wr_step1, wr_step2]
                else:
                    step_sizes = [float(step1), float(step2), float(step3)]
                    wr_step_sizes_val = [wr_step1, wr_step2, wr_step3]
                
                st.caption(f"📌 实际迭代轮数: {len(step_sizes)} 轮，mol步长: {step_sizes}，WR步长: {wr_step_sizes_val}")
            else:
                step_sizes = None
                wr_step_sizes_val = None
            
            st.markdown("**组分范围限制**")
            use_custom_ranges = st.checkbox(
                "自定义组分取值范围",
                value=False,
                help="限制各组分的取值范围（mol 比例加起来仍为 100%）",
            )
            
            if use_custom_ranges:
                st.caption("阳离子脂质/mRNA 重量比")
                col1, col2 = st.columns(2)
                with col1:
                    weight_ratio_min = st.number_input("最小", min_value=1.0, max_value=50.0, value=5.0, step=1.0, format="%.1f", key="wr_min")
                with col2:
                    weight_ratio_max = st.number_input("最大", min_value=1.0, max_value=50.0, value=30.0, step=1.0, format="%.1f", key="wr_max")
                
                st.caption("阳离子脂质 mol 比例 (%)")
                col1, col2 = st.columns(2)
                with col1:
                    cationic_mol_min = st.number_input("最小", min_value=0.0, max_value=100.0, value=5.0, step=5.0, format="%.1f", key="cat_min")
                with col2:
                    cationic_mol_max = st.number_input("最大", min_value=0.0, max_value=100.0, value=80.0, step=5.0, format="%.1f", key="cat_max")
                
                st.caption("磷脂 mol 比例 (%)")
                col1, col2 = st.columns(2)
                with col1:
                    phospholipid_mol_min = st.number_input("最小", min_value=0.0, max_value=100.0, value=0.0, step=5.0, format="%.1f", key="phos_min")
                with col2:
                    phospholipid_mol_max = st.number_input("最大", min_value=0.0, max_value=100.0, value=80.0, step=5.0, format="%.1f", key="phos_max")
                
                st.caption("胆固醇 mol 比例 (%)")
                col1, col2 = st.columns(2)
                with col1:
                    cholesterol_mol_min = st.number_input("最小", min_value=0.0, max_value=100.0, value=0.0, step=5.0, format="%.1f", key="chol_min")
                with col2:
                    cholesterol_mol_max = st.number_input("最大", min_value=0.0, max_value=100.0, value=80.0, step=5.0, format="%.1f", key="chol_max")
                
                st.caption("PEG 脂质 mol 比例 (%)")
                col1, col2 = st.columns(2)
                with col1:
                    peg_mol_min = st.number_input("最小", min_value=0.0, max_value=20.0, value=0.0, step=1.0, format="%.1f", key="peg_min")
                with col2:
                    peg_mol_max = st.number_input("最大", min_value=0.0, max_value=20.0, value=5.0, step=1.0, format="%.1f", key="peg_max")
                
                comp_ranges = {
                    "weight_ratio_min": weight_ratio_min,
                    "weight_ratio_max": weight_ratio_max,
                    "cationic_mol_min": cationic_mol_min,
                    "cationic_mol_max": cationic_mol_max,
                    "phospholipid_mol_min": phospholipid_mol_min,
                    "phospholipid_mol_max": phospholipid_mol_max,
                    "cholesterol_mol_min": cholesterol_mol_min,
                    "cholesterol_mol_max": cholesterol_mol_max,
                    "peg_mol_min": peg_mol_min,
                    "peg_mol_max": peg_mol_max,
                }
                
                min_sum = cationic_mol_min + phospholipid_mol_min + cholesterol_mol_min + peg_mol_min
                max_sum = cationic_mol_max + phospholipid_mol_max + cholesterol_mol_max + peg_mol_max
                if min_sum > 100.0 or max_sum < 100.0:
                    st.warning("⚠️ 当前范围设置可能无法生成有效配方（mol 比例需加起来为 100%）")
            else:
                comp_ranges = None
            
            st.markdown("**评分/排序权重**")
            use_custom_scoring = st.checkbox(
                "自定义评分权重",
                value=False,
                help="默认仅按目标器官分布排序。开启后可自定义多目标加权评分，总分 = 各项score之和。",
            )
            
            if use_custom_scoring:
                st.caption("**回归任务权重**")
                
                sw_biodist = st.number_input(
                    "器官分布 (Biodistribution)",
                    min_value=0.00, max_value=10.00, value=0.30,
                    step=0.05, format="%.2f", key="sw_biodist",
                    help="score = biodist_value × weight",
                )
                sw_delivery = st.number_input(
                    "量化递送 (Quantified Delivery)",
                    min_value=0.00, max_value=10.00, value=0.25,
                    step=0.05, format="%.2f", key="sw_delivery",
                    help="score = normalize(delivery, route) × weight",
                )
                sw_size = st.number_input(
                    "粒径 (Size, 80-150nm)",
                    min_value=0.00, max_value=10.00, value=0.05,
                    step=0.05, format="%.2f", key="sw_size",
                    help="score = (1 if 60≤size≤150 else 0) × weight",
                )
                
                st.caption("**包封率 (EE) 分类权重**")
                col1, col2, col3 = st.columns(3)
                with col1:
                    sw_ee0 = st.number_input("<50% (低)", min_value=0.00, max_value=1.00, value=0.00, step=0.01, format="%.2f", key="sw_ee0")
                with col2:
                    sw_ee1 = st.number_input("50-80% (中)", min_value=0.00, max_value=1.00, value=0.02, step=0.01, format="%.2f", key="sw_ee1")
                with col3:
                    sw_ee2 = st.number_input(">80% (高)", min_value=0.00, max_value=1.00, value=0.08, step=0.01, format="%.2f", key="sw_ee2")
                
                st.caption("**PDI 分类权重**")
                col1, col2, col3, col4 = st.columns(4)
                with col1:
                    sw_pdi0 = st.number_input("<0.2 (优)", min_value=0.00, max_value=1.00, value=0.08, step=0.01, format="%.2f", key="sw_pdi0")
                with col2:
                    sw_pdi1 = st.number_input("0.2-0.3 (良)", min_value=0.00, max_value=1.00, value=0.02, step=0.01, format="%.2f", key="sw_pdi1")
                with col3:
                    sw_pdi2 = st.number_input("0.3-0.4 (中)", min_value=0.00, max_value=1.00, value=0.00, step=0.01, format="%.2f", key="sw_pdi2")
                with col4:
                    sw_pdi3 = st.number_input(">0.4 (差)", min_value=0.00, max_value=1.00, value=0.00, step=0.01, format="%.2f", key="sw_pdi3")
                
                st.caption("**毒性分类权重**")
                col1, col2 = st.columns(2)
                with col1:
                    sw_toxic0 = st.number_input("无毒", min_value=0.00, max_value=1.00, value=0.20, step=0.05, format="%.2f", key="sw_toxic0")
                with col2:
                    sw_toxic1 = st.number_input("有毒", min_value=0.00, max_value=1.00, value=0.00, step=0.05, format="%.2f", key="sw_toxic1")
                
                scoring_weights = {
                    "biodist_weight": sw_biodist,
                    "delivery_weight": sw_delivery,
                    "size_weight": sw_size,
                    "ee_class_weights": [sw_ee0, sw_ee1, sw_ee2],
                    "pdi_class_weights": [sw_pdi0, sw_pdi1, sw_pdi2, sw_pdi3],
                    "toxic_class_weights": [sw_toxic0, sw_toxic1],
                }
            else:
                scoring_weights = None  # 使用默认值（仅按 biodist 排序）
        
        st.divider()
        
        # 优化按钮
        optimize_button = st.button(
            "🚀 开始配方优选",
            type="primary",
            use_container_width=True,
            disabled=not api_online or not smiles_input.strip() or not selected_routes,
        )
    
    # ========== 主内容区 ==========
    
    # 使用 session state 存储结果
    if "results" not in st.session_state:
        st.session_state["results"] = None
    if "results_df" not in st.session_state:
        st.session_state["results_df"] = None
    
    # 执行优化
    if optimize_button and smiles_input.strip():
        # 解析多条 SMILES（用逗号分隔）
        smiles_list = [s.strip() for s in smiles_input.split(",") if s.strip()]
        
        if not smiles_list:
            st.error("❌ 请输入有效的 SMILES 字符串")
        else:
            is_multi_smiles = len(smiles_list) > 1
            all_results = []
            all_dfs = []
            errors = []
            
            # 进度条
            progress_bar = st.progress(0)
            status_text = st.empty()
            
            for idx, smiles in enumerate(smiles_list):
                status_text.text(f"🔄 正在优化 SMILES {idx + 1}/{len(smiles_list)}...")
                progress_bar.progress((idx) / len(smiles_list))
                
                try:
                    results = call_optimize_api(
                        smiles=smiles,
                        organ=selected_organ,
                        top_k=top_k,
                        num_seeds=num_seeds,
                        top_per_seed=top_per_seed,
                        step_sizes=step_sizes,
                        wr_step_sizes=wr_step_sizes_val,
                        comp_ranges=comp_ranges,
                        routes=selected_routes,
                        scoring_weights=scoring_weights,
                    )
                    all_results.append({"smiles": smiles, "results": results})
                    
                    # 为多 SMILES 模式添加 SMILES 标签
                    smiles_label = smiles[:30] + "..." if len(smiles) > 30 else smiles
                    df = format_results_dataframe(results, smiles_label if is_multi_smiles else None)
                    all_dfs.append(df)
                    
                except httpx.HTTPStatusError as e:
                    try:
                        error_detail = e.response.json().get("detail", str(e))
                    except:
                        error_detail = str(e)
                    errors.append(f"SMILES {idx + 1}: {error_detail}")
                except httpx.RequestError as e:
                    errors.append(f"SMILES {idx + 1}: API 连接失败 - {e}")
                except Exception as e:
                    errors.append(f"SMILES {idx + 1}: {e}")
            
            progress_bar.progress(1.0)
            status_text.empty()
            progress_bar.empty()
            
            # 显示错误
            for err in errors:
                st.error(f"❌ {err}")
            
            # 保存结果
            if all_results:
                st.session_state["results"] = all_results[0]["results"] if len(all_results) == 1 else all_results
                st.session_state["results_df"] = pd.concat(all_dfs, ignore_index=True) if all_dfs else None
                st.session_state["smiles_used"] = smiles_list
                st.session_state["organ_used"] = selected_organ
                st.session_state["is_multi_smiles"] = is_multi_smiles
                st.success(f"✅ 优化完成！成功处理 {len(all_results)}/{len(smiles_list)} 条 SMILES")
    
    # 显示结果
    if st.session_state["results"] is not None and st.session_state["results_df"] is not None:
        results = st.session_state["results"]
        df = st.session_state["results_df"]
        is_multi_smiles = st.session_state.get("is_multi_smiles", False)
        
        # 结果概览
        if is_multi_smiles:
            # 多 SMILES 模式
            col1, col2, col3 = st.columns(3)
            
            with col1:
                # 获取 target_organ（从第一个结果）
                first_result = results[0]["results"] if isinstance(results, list) else results
                target_organ = first_result["target_organ"]
                st.metric(
                    "目标器官",
                    ORGAN_LABELS.get(target_organ, target_organ).split(" ")[0],
                )
            
            with col2:
                st.metric(
                    "SMILES 数量",
                    len(results) if isinstance(results, list) else 1,
                )
            
            with col3:
                st.metric(
                    "总配方数",
                    len(df),
                )
        else:
            # 单 SMILES 模式
            col1, col2, col3 = st.columns(3)
            
            with col1:
                st.metric(
                    "目标器官",
                    ORGAN_LABELS.get(results["target_organ"], results["target_organ"]).split(" ")[0],
                )
            
            with col2:
                best_score = results["formulations"][0]["target_biodist"]
                st.metric(
                    "最优分布",
                    f"{best_score*100:.2f}%",
                )
            
            with col3:
                st.metric(
                    "优选配方数",
                    len(results["formulations"]),
                )
        
        st.divider()
        
        # 结果表格
        st.subheader("📊 优选配方列表")
        
        # 导出按钮行
        col_export, col_spacer = st.columns([1, 4])
        with col_export:
            smiles_used = st.session_state.get("smiles_used", "")
            if isinstance(smiles_used, list):
                smiles_used = ",".join(smiles_used)
            
            csv_content = create_export_csv(
                df,
                smiles_used,
                st.session_state.get("organ_used", ""),
            )
            
            # 获取 target_organ
            if is_multi_smiles:
                target_organ = results[0]["results"]["target_organ"] if isinstance(results, list) else results["target_organ"]
            else:
                target_organ = results["target_organ"]
            
            st.download_button(
                label="📥 导出 CSV",
                data=csv_content,
                file_name=f"lnp_optimization_{target_organ}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
                mime="text/csv",
            )
        
        # 显示表格
        st.dataframe(
            df,
            use_container_width=True,
            hide_index=True,
            height=600,
        )
        
        # 详细信息
        # with st.expander("🔍 查看最优配方详情"):
        #     best = results["formulations"][0]
            
        #     col1, col2 = st.columns(2)
            
        #     with col1:
        #         st.markdown("**配方参数**")
        #         st.json({
        #             "阳离子脂质/mRNA 比例": best["cationic_lipid_to_mrna_ratio"],
        #             "阳离子脂质 (mol%)": best["cationic_lipid_mol_ratio"],
        #             "磷脂 (mol%)": best["phospholipid_mol_ratio"],
        #             "胆固醇 (mol%)": best["cholesterol_mol_ratio"],
        #             "PEG 脂质 (mol%)": best["peg_lipid_mol_ratio"],
        #             "辅助脂质": best["helper_lipid"],
        #             "给药途径": best["route"],
        #         })
            
        #     with col2:
        #         st.markdown("**各器官 Biodistribution 预测**")
        #         biodist_df = pd.DataFrame([
        #             {"器官": ORGAN_LABELS.get(k, k), "Biodistribution": f"{v:.4f}"}
        #             for k, v in best["all_biodist"].items()
        #         ])
        #         st.dataframe(biodist_df, hide_index=True, use_container_width=True)
    
    else:
        # 欢迎信息
        st.info("👈 请在左侧输入 SMILES 并选择目标器官，然后点击「开始配方优选」")
        
        # 使用说明
        # with st.expander("📖 使用说明"):
        #     st.markdown("""
        #     ### 如何使用
            
        #     1. **输入 SMILES**: 在左侧输入框中输入阳离子脂质的 SMILES 字符串
        #     2. **选择目标器官**: 选择您希望优化的器官靶向
        #     3. **点击优选**: 系统将自动搜索最优配方组合
        #     4. **查看结果**: 右侧将显示 Top-20 优选配方
        #     5. **导出数据**: 点击导出按钮将结果保存为 CSV 文件
            
        #     ### 优化参数
            
        #     系统会优化以下配方参数:
        #     - **阳离子脂质/mRNA 比例**: 0.05 - 0.30
        #     - **阳离子脂质 mol 比例**: 0.05 - 0.80
        #     - **磷脂 mol 比例**: 0.00 - 0.80
        #     - **胆固醇 mol 比例**: 0.00 - 0.80
        #     - **PEG 脂质 mol 比例**: 0.00 - 0.05
        #     - **辅助脂质**: DOPE / DSPC / DOTAP
        #     - **给药途径**: 静脉注射 / 肌肉注射
            
        #     ### 约束条件
            
        #     mol 比例之和 = 1 (阳离子脂质 + 磷脂 + 胆固醇 + PEG 脂质)
        #     """)


if __name__ == "__main__":
    main()

