// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::path::PathBuf;
use std::process::ExitCode;

/// MCP 进程本地时区日志时间戳格式化器(与 GUI lib.rs 同款,对齐日志格式)。
/// tracing_subscriber 默认输出 UTC,改为 chrono::Local 输出含时区偏移的本地时间。
struct LocalTimer;
impl tracing_subscriber::fmt::time::FormatTime for LocalTimer {
    fn format_time(&self, w: &mut tracing_subscriber::fmt::format::Writer<'_>) -> std::fmt::Result {
        write!(w, "{}", chrono::Local::now().format("%Y-%m-%dT%H:%M:%S%.6f%:z"))
    }
}

/// 初始化 MCP 进程的文件日志:追加到 %TEMP%/devflow-trace.log(与 GUI 同文件),
/// RUST_LOG 控制级别(默认 info)。返回的 guard 需保持存活到 server 退出,
/// 否则 non_blocking worker 提前关闭会丢失日志。
fn init_mcp_tracing() -> tracing_appender::non_blocking::WorkerGuard {
    let log_path = std::env::temp_dir().join("devflow-trace.log");
    let log_file = std::fs::OpenOptions::new()
        .create(true)
        .append(true)
        .open(&log_path)
        .expect("创建日志文件失败");
    let (non_blocking, guard) = tracing_appender::non_blocking(log_file);
    tracing_subscriber::fmt()
        .with_timer(LocalTimer)
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info"))
        )
        .with_writer(non_blocking)
        .with_ansi(false)
        .init();
    guard
}

fn main() -> ExitCode {
    // CLI 子命令:手动解析 argv(避免引入 clap 重依赖)。
    //
    // `devflow mcp-server [--db <path>] [--read-only] [--stdio] [--idle-timeout <secs>] [--print-config]`
    //
    // 仅识别首个非程序名参数是否为 `mcp-server`;其余情况走 GUI。
    // stdio 句柄由父进程(MCP 客户端)继承,无需额外配置。
    let args: Vec<String> = std::env::args().collect();
    if args.iter().nth(1).map(|s| s.as_str()) == Some("mcp-server") {
        return run_mcp_server(&args[2..]);
    }
    devflow_lib::run();
    ExitCode::SUCCESS
}

/// 解析 mcp-server 子命令参数并启动 MCP server。
///
/// - `--db <path>`:指定 SQLite 路径(默认:系统 app_data_dir/devflow[-dev].db)
/// - `--read-only`:仅暴露 list/get 工具(生产环境建议开启,拒绝全部写库)
/// - `--stdio`:显式声明 stdio 形态(默认即 stdio;headless/CI/GUI 未启动场景)
/// - `--idle-timeout <secs>`:空闲 N 秒无请求自动退出(0=禁用;默认 60)
/// - `--print-config`:输出 MCP 配置到 stdout 后退出(默认 HTTP 形态,加 --stdio 输出 stdio command 形态)
fn run_mcp_server(args: &[String]) -> ExitCode {
    let mut db_path: Option<PathBuf> = None;
    let mut read_only = false;
    let mut stdio_mode = false;
    let mut print_config = false;
    // 空闲超时:None=未显式指定(用默认 60s);Some(0)=禁用;Some(n)=n 秒
    let mut idle_timeout_arg: Option<u64> = None;

    let mut i = 0;
    while i < args.len() {
        match args[i].as_str() {
            "--db" => {
                i += 1;
                if i >= args.len() {
                    eprintln!("--db 需要参数");
                    return ExitCode::FAILURE;
                }
                db_path = Some(PathBuf::from(&args[i]));
            }
            "--read-only" => read_only = true,
            "--stdio" => stdio_mode = true,
            "--print-config" => print_config = true,
            "--idle-timeout" => {
                i += 1;
                if i >= args.len() {
                    eprintln!("--idle-timeout 需要参数(整数秒,0=禁用)");
                    return ExitCode::FAILURE;
                }
                match args[i].parse::<u64>() {
                    Ok(secs) => idle_timeout_arg = Some(secs),
                    Err(_) => {
                        eprintln!("--idle-timeout 参数需为整数秒: {}", args[i]);
                        return ExitCode::FAILURE;
                    }
                }
            }
            "-h" | "--help" => {
                println!("devflow mcp-server [--db <path>] [--read-only] [--stdio] [--idle-timeout <secs>] [--print-config]");
                println!();
                println!("  --db <path>           指定 SQLite 数据库路径(默认:app_data_dir/<identifier>/devflow[-dev].db)");
                println!("  --read-only           仅暴露 list/get 工具(拒绝全部写库,生产环境建议开启)");
                println!("  --stdio               显式声明 stdio 形态(默认即 stdio;headless/CI/GUI 未启动场景)");
                println!("  --idle-timeout <secs> 空闲 N 秒无请求自动退出(防孤儿进程残留;0=禁用;默认 60)");
                println!("  --print-config        输出 MCP 配置(默认 HTTP,加 --stdio 输出 stdio command 形态)");
                return ExitCode::SUCCESS;
            }
            other => {
                eprintln!("未知参数: {other}(用 --help 查看)");
                return ExitCode::FAILURE;
            }
        }
        i += 1;
    }

    if print_config {
        // 说明性注释(非 JSON)打 stderr,保证 stdout 是纯 JSON 可直接被客户端消费。
        if !stdio_mode {
            // 默认输出 HTTP 形态:桌面进程内嵌 HTTP MCP server + 托盘常驻,
            // Claude Code 用 --transport http 直连同一进程。端口 18765 与
            // crates/df-mcp/src/server_http.rs 的 DEFAULT_MCP_PORT 对齐(本文件不 import,直接写死)。
            let json = r#"{"mcpServers":{"devflow":{"transport":"http","url":"http://127.0.0.1:18765/mcp"}}}"#;
            println!("{json}");
            eprintln!("# Claude Code 接入(需先启动 DevFlow 桌面进程,托盘常驻):");
            eprintln!("#   claude mcp add --transport http devflow http://127.0.0.1:18765/mcp");
            eprintln!("# stdio 备选(无 GUI 场景):");
            eprintln!("#   devflow mcp-server --stdio --print-config");
            return ExitCode::SUCCESS;
        }

        // 输出 Claude Code / Cursor 兼容的 MCP 配置片段(command/args 形态,显式带 --stdio)。
        // Claude Code: claude mcp add devflow -- devflow mcp-server --stdio [--read-only] [--idle-timeout N]
        // Cursor: 在 ~/.cursor/mcp.json 加 mcpServers.devflow
        let read_only_flag = if read_only { r#","--read-only""# } else { "" };
        // 空闲超时:用户显式指定过才写进配置片段(未指定由 server 用默认 60s,不必冗余)。
        let idle_flag = match idle_timeout_arg {
            Some(secs) => format!(r#","--idle-timeout","{secs}""#),
            None => String::new(),
        };
        // 用当前可执行文件绝对路径(command 需要能被客户端直接执行;硬编码 devflow
        // 在 Windows 上是 DevFlow.exe,且 PATH 未必含安装目录)。
        let exe = std::env::current_exe()
            .map(|p| p.to_string_lossy().replace('\\', "/"))
            .unwrap_or_else(|_| "devflow".to_owned());
        let json = format!(
            r#"{{"mcpServers":{{"devflow":{{"command":"{exe}","args":["mcp-server","--stdio"{read_only_flag}{idle_flag}]}}}}}}"#
        );
        println!("{json}");
        eprintln!("# Claude Code 接入(stdio 形态):");
        eprintln!("#   claude mcp add devflow -- {exe} mcp-server --stdio");
        eprintln!("# Cursor 接入:把上面 JSON 写入 ~/.cursor/mcp.json");
        eprintln!("# 安全提示:生产环境建议加 --read-only(只读),写库请在 DevFlow 应用内操作");
        return ExitCode::SUCCESS;
    }

    // 解析 db 路径(未指定则用系统 app_data_dir)
    let db_path = match db_path {
        Some(p) => p,
        None => match default_db_path() {
            Ok(p) => p,
            Err(e) => {
                eprintln!("无法定位默认数据库目录: {e}");
                eprintln!("请用 --db <path> 显式指定");
                return ExitCode::FAILURE;
            }
        },
    };

    // MCP 是独立进程,不经 GUI lib.rs 的 run() 路径,须单独 init tracing subscriber;
    // 否则 df_mcp 内 medium_audit 的 tracing::warn! 无 subscriber 是 no-op,审计不落盘。
    // guard 绑定在此函数作用域,存活到 server 退出,保证日志 worker 持续运行。
    let _log_guard = init_mcp_tracing();
    tracing::info!(path = %db_path.display(), "[startup] MCP server 日志已初始化");

    // 空闲超时:未显式指定用默认 60s(对齐 ServerConfig::default);显式 0 = 禁用(常驻)。
    let idle_timeout = match idle_timeout_arg {
        Some(0) => None,
        Some(secs) => Some(std::time::Duration::from_secs(secs)),
        None => Some(std::time::Duration::from_secs(60)),
    };
    let config = df_mcp::ServerConfig {
        read_only,
        idle_timeout,
        // 写操作回调:GUI 内嵌 HTTP 形态经 src-tauri/src/mcp.rs → on_tool_call 已接
        // emit df-data-changed 刷新前端;stdio 独立进程暂无 AppHandle,暂传 None,
        // 架构上预留接线点,后续注入 AppHandle 即可让 stdio 形态 MCP 写库也触发 GUI 刷新。
        on_write_call: None,
    };

    // 启动 MCP server(tokio runtime)
    let rt = match tokio::runtime::Runtime::new() {
        Ok(rt) => rt,
        Err(e) => {
            eprintln!("启动 tokio runtime 失败: {e}");
            return ExitCode::FAILURE;
        }
    };
    match rt.block_on(df_mcp::run_server(&db_path, config)) {
        Ok(()) => ExitCode::SUCCESS,
        Err(e) => {
            eprintln!("MCP server 异常退出: {e}");
            ExitCode::FAILURE
        }
    }
}

/// 默认数据库路径:与 GUI 应用同库(系统 app_data_dir/{identifier}/devflow[-dev].db)。
///
/// GUI 模式通过 Tauri 的 `app.path().app_data_dir()` 获取路径(含 identifier),
/// CLI 模式无 app handle,改用编译时注入的 MCP_APP_IDENTIFIER 拼出相同路径。
/// 保证 MCP server 与 GUI 读写同一数据库,无需手动传 --db。
fn default_db_path() -> anyhow::Result<PathBuf> {
    let base = if cfg!(target_os = "windows") {
        std::env::var("APPDATA").map(PathBuf::from)?
    } else if cfg!(target_os = "macos") {
        let home = std::env::var("HOME").map(PathBuf::from)?;
        home.join("Library/Application Support")
    } else {
        let home = std::env::var("HOME").map(PathBuf::from)?;
        home.join(".local/share")
    };
    // 从编译时环境变量 MCP_APP_IDENTIFIER 读取 Tauri identifier(如 top.1216.devflow),
    // 与 tauri::path::PathResolver::app_data_dir 行为一致,拼出正确路径。
    let identifier = option_env!("MCP_APP_IDENTIFIER").unwrap_or("devflow");
    let dir = base.join(identifier);
    std::fs::create_dir_all(&dir)?;
    let name = if cfg!(debug_assertions) {
        "devflow-dev.db"
    } else {
        "devflow.db"
    };
    Ok(dir.join(name))
}
