use std::process::{Child, Command, Stdio};
use std::sync::Mutex;
use tauri::Manager;

struct StreamlitProcess(Mutex<Option<Child>>);

/// 等待指定端口可连接，最多等待 timeout_secs 秒
fn wait_for_port(host: &str, port: u16, timeout_secs: u64) -> bool {
    let start = std::time::Instant::now();
    while start.elapsed() < std::time::Duration::from_secs(timeout_secs) {
        if std::net::TcpStream::connect((host, port)).is_ok() {
            return true;
        }
        std::thread::sleep(std::time::Duration::from_millis(200));
    }
    false
}

/// 停止 Streamlit 子进程
///
/// - Unix: 先 SIGTERM（优雅退出），等待 3 秒无响应后 SIGKILL
/// - Windows: 直接 TerminateProcess
fn kill_streamlit(child: &mut Child) {
    #[cfg(unix)]
    {
        // 先发 SIGTERM 请求优雅退出
        let _ = Command::new("kill")
            .arg("-TERM")
            .arg(child.id().to_string())
            .spawn();
        std::thread::sleep(std::time::Duration::from_secs(3));

        // 尝试 wait（如果已退出则返回 Ok(Some(status))）
        if let Ok(Some(_)) = child.try_wait() {
            log::info!("Streamlit 进程已优雅退出");
            return;
        }
        log::warn!("Streamlit 进程未响应 SIGTERM，强制终止...");
    }

    // 强制终止
    let _ = child.kill();
    let _ = child.wait();
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    let app = tauri::Builder::default()
        .setup(|app| {
            if cfg!(debug_assertions) {
                app.handle().plugin(
                    tauri_plugin_log::Builder::default()
                        .level(log::LevelFilter::Info)
                        .build(),
                )?;
            }

            let child = if cfg!(debug_assertions) {
                // ── 开发模式 ── 使用系统安装的 streamlit ──
                let manifest_dir =
                    std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
                let project_root = manifest_dir.parent().unwrap_or(&manifest_dir);
                let script_path = project_root.join("geo_tool.py");

                log::info!(
                    "[开发模式] 启动 Streamlit: {:?}",
                    script_path
                );

                Command::new("streamlit")
                    .args([
                        "run",
                        script_path.to_str().unwrap_or("geo_tool.py"),
                        "--server.port",
                        "8501",
                        "--server.address",
                        "127.0.0.1",
                        "--server.headless",
                        "true",
                        "--browser.gatherUsageStats",
                        "false",
                        "--logger.level",
                        "error",
                    ])
                    .current_dir(project_root)
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .spawn()
            } else {
                // ── 生产模式 ── 使用 PyInstaller 打包的独立可执行文件 ──
                let resource_dir = app
                    .path()
                    .resource_dir()
                    .expect("无法获取资源目录");

                let exe_name = if cfg!(target_os = "windows") {
                    "geo_tool_app.exe"
                } else {
                    "geo_tool_app"
                };
                let exe_path = resource_dir.join(exe_name);

                log::info!(
                    "[生产模式] 启动打包应用: {:?}",
                    exe_path
                );

                let mut cmd = Command::new(&exe_path);
                cmd.current_dir(&resource_dir)
                    .stdin(Stdio::null())
                    .stdout(Stdio::null())
                    .stderr(Stdio::null());

                // Windows: 不显示控制台窗口
                #[cfg(target_os = "windows")]
                {
                    use std::os::windows::process::CommandExt;
                    const CREATE_NO_WINDOW: u32 = 0x08000000u32;
                    cmd.creation_flags(CREATE_NO_WINDOW);
                }

                cmd.spawn()
            };

            match child {
                Ok(child) => {
                    log::info!("Streamlit 进程已启动 (PID: {})", child.id());
                    app.manage(StreamlitProcess(Mutex::new(Some(child))));
                }
                Err(e) => {
                    log::error!("启动 Streamlit 失败: {}", e);
                    eprintln!(
                        "错误：无法启动 Streamlit 服务。请确保已安装 streamlit。\n  {}",
                        e
                    );
                }
            }

            // 等待 Streamlit 就绪（最多 15 秒）
            if !wait_for_port("127.0.0.1", 8501, 15) {
                log::warn!("Streamlit 在 15 秒内未能就绪");
            } else {
                log::info!("Streamlit 已就绪 (127.0.0.1:8501)");
            }

            Ok(())
        })
        .build(tauri::generate_context!())
        .expect("error while building tauri application");

    app.run(|app_handle, event| {
        // 窗口关闭 → 停止子进程 → 退出应用
        if let tauri::RunEvent::ExitRequested { .. } = event {
            if let Some(state) = app_handle.try_state::<StreamlitProcess>() {
                if let Ok(mut guard) = state.0.lock() {
                    if let Some(ref mut child) = *guard {
                        log::info!("正在停止 Streamlit 进程...");
                        kill_streamlit(child);
                        log::info!("Streamlit 进程已停止");
                    }
                }
            }
            // 确保应用进程完全退出
            std::process::exit(0);
        }
    });
}
