//! cc-router 桌面 app 入口。
//!
//! 这里的 `run()` 是 Tauri 生命周期起点；桌面壳和代理服务、SQLite、Provider 加载
//! 全部在 `setup()` 中完成初始化。模块粒度见 plan §2。

pub mod commands;
pub mod db;
pub mod error;
pub mod oauth;
pub mod observability;
pub mod provider;
pub mod proxy;
pub mod settings;
pub mod state;
pub mod subscription;
pub mod tls;
pub mod tray;
pub mod updater_source;
pub mod virtual_model;

use std::sync::Arc;

use tauri::Manager;
use tokio::sync::{mpsc, RwLock};
use tracing::{error, info};

use crate::state::AppState;

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_clipboard_manager::init())
        .plugin(tauri_plugin_updater::Builder::new().build())
        .setup(|app| {
            // 日志初始化
            let app_data_dir = app
                .path()
                .app_data_dir()
                .expect("无法解析 app_data_dir");
            observability::logger::init(&app_data_dir)?;
            info!(?app_data_dir, "cc-router starting");

            // 解析 provider YAML 资源目录
            let resource_dir = app
                .path()
                .resource_dir()
                .expect("无法解析 resource_dir");

            // 异步初始化：数据库 + providers + 订阅运行时 + 代理
            let handle = app.handle().clone();
            tauri::async_runtime::block_on(async move {
                match bootstrap(handle.clone(), app_data_dir, resource_dir).await {
                    Ok(state) => {
                        handle.manage(state);
                    }
                    Err(e) => {
                        error!(?e, "bootstrap failed");
                        std::process::exit(1);
                    }
                }
            });

            // 系统托盘
            if let Err(e) = tray::setup(app) {
                error!(?e, "tray setup failed");
            }

            Ok(())
        })
        .on_window_event(tray::on_window_event)
        .invoke_handler(tauri::generate_handler![
            commands::providers::list_providers,
            commands::subscriptions::list_subscriptions,
            commands::subscriptions::get_subscription,
            commands::subscriptions::create_subscription,
            commands::subscriptions::update_subscription,
            commands::subscriptions::update_subscription_key,
            commands::subscriptions::delete_subscription,
            commands::subscriptions::set_subscription_enabled,
            commands::subscriptions::test_connection,
            commands::subscriptions::refresh_model_list,
            commands::subscriptions::refresh_subscription_balance,
            commands::virtual_models::list_virtual_models,
            commands::virtual_models::update_virtual_model,
            commands::requests::list_requests,
            commands::requests::list_supported_client_tools,
            commands::statistics::get_overall_stats,
            commands::statistics::get_daily_series,
            commands::statistics::get_breakdown,
            commands::statistics::get_token_heatmap,
            commands::receipts::get_receipt_summary,
            commands::events::list_events,
            commands::settings::get_settings,
            commands::settings::update_settings,
            commands::settings::generate_new_token,
            commands::proxy::proxy_status,
            commands::proxy::env_snippet,
            commands::onboarding::get_onboarding_state,
            commands::onboarding::complete_onboarding,
            commands::app::factory_reset,
            commands::app::is_appimage_runtime,
            commands::app::relaunch_app,
            commands::updater::check_for_update,
            commands::updater::download_install_update,
            commands::debug::open_debug_dump_dir,
            commands::debug::clear_debug_dumps,
            commands::oauth::start_chatgpt_device_flow,
            commands::oauth::poll_chatgpt_device_code,
            commands::oauth::create_chatgpt_oauth_subscription,
            commands::oauth::forget_chatgpt_oauth_cache,
            commands::oauth::get_chatgpt_oauth_usage,
            commands::oauth::import_kiro_credentials_from_file,
            commands::oauth::import_kiro_credentials_from_text,
            commands::oauth::start_kiro_device_flow,
            commands::oauth::poll_kiro_device_code,
            commands::oauth::create_kiro_subscription,
            commands::oauth::forget_kiro_oauth_cache,
            commands::oauth::update_kiro_disguise_fields,
            commands::tls::tls_get_status,
            commands::tls::tls_get_ca_pem_path,
            commands::tls::tls_export_ca_pem,
            commands::tls::tls_regenerate_leaf,
        ])
        .run(tauri::generate_context!())
        .expect("运行 cc-router 时发生错误");
}

async fn bootstrap(
    handle: tauri::AppHandle,
    app_data_dir: std::path::PathBuf,
    resource_dir: std::path::PathBuf,
) -> anyhow::Result<AppState> {
    // 1. DB
    let db_path = app_data_dir.join("config.db");
    let pool = db::init_pool(&db_path).await?;
    db::run_migrations(&pool, &resource_dir).await?;

    // 2. Provider YAML 加载
    let providers = provider::loader::load_all(&resource_dir)?;
    info!(provider_count = providers.len(), "providers loaded");

    // 3. Settings
    let mut settings = settings::load_or_default(&app_data_dir).await?;
    // 首次启动或老用户升级时,auth_token 为空 → 生成并立即 save。
    settings::ensure_auth_token(&app_data_dir, &mut settings).await?;

    // 4. 订阅运行时状态初始化
    let subscription_map = subscription::store::load_runtime(&pool).await?;

    // 5. 虚拟模型绑定
    let virtual_models = virtual_model::store::load_all(&pool).await?;

    // 6. 请求日志 channel
    let (log_tx, log_rx) = mpsc::channel(1024);
    let log_pool = pool.clone();
    let log_handle = handle.clone();
    tauri::async_runtime::spawn(async move {
        observability::request_log::run_consumer(log_pool, log_rx, log_handle).await;
    });

    // 6b. 事件流 channel (kind=request/subscription_state_change/system_error)
    let (event_tx, event_rx) = mpsc::channel(1024);
    let event_pool = pool.clone();
    let event_handle = handle.clone();
    tauri::async_runtime::spawn(async move {
        observability::events::run_consumer(event_pool, event_rx, event_handle).await;
    });

    // 6c. 调试模式 body dump channel (调试模式开启时由 pipeline / sse 插桩点投递)
    let (body_dump_tx, body_dump_rx) = mpsc::channel(256);
    let dump_dir = observability::body_dump::dump_dir(&app_data_dir);
    tauri::async_runtime::spawn(async move {
        observability::body_dump::run_consumer(body_dump_rx, dump_dir).await;
    });

    // 7. HTTP client 单例
    // timeout(600s) 是整个 request 生命周期上限(含流式 body),与 Anthropic server-side 上限对齐;
    // 主要在真 hang 时兜底,正常 SSE 客户端断开会通过 client_tx 失败立即释放(见 sse.rs)。
    let http_client = reqwest::Client::builder()
        .connect_timeout(std::time::Duration::from_secs(10))
        .timeout(std::time::Duration::from_secs(600))
        .user_agent(concat!("cc-router/", env!("CARGO_PKG_VERSION")))
        .build()?;

    // probe_client: 仅 ping/测试连接用, 短超时, 与生产路径分离
    let probe_client = reqwest::Client::builder()
        .connect_timeout(std::time::Duration::from_secs(10))
        .timeout(std::time::Duration::from_secs(30))
        .user_agent(concat!("cc-router-probe/", env!("CARGO_PKG_VERSION")))
        .build()?;

    let chatgpt_oauth = Arc::new(oauth::chatgpt::ChatGptOAuthManager::new(pool.clone()));
    let kiro_oauth = Arc::new(oauth::kiro::KiroOAuthManager::new(pool.clone()));

    // TLS 初始化: 只在 proxy_mode 包含 HTTPS 时加载/生成证书. HTTP-only 模式下 None,
    // 切到 HTTPS 后由用户重启 app 触发. 失败 fatal (HTTPS 模式但起不来比 fallback 到 HTTP 更安全).
    let tls_config = if settings.proxy_mode.includes_https() {
        Some(
            tls::load_or_init_server_config(
                &app_data_dir,
                &settings.tls_extra_sans,
                settings.https_enable_h2,
            )
            .await?,
        )
    } else {
        None
    };

    let state = AppState {
        db: pool,
        providers: Arc::new(providers),
        subscriptions: Arc::new(RwLock::new(subscription_map)),
        virtual_models: Arc::new(RwLock::new(virtual_models)),
        settings: Arc::new(RwLock::new(settings)),
        http_bound_port: Arc::new(RwLock::new(None)),
        https_bound_port: Arc::new(RwLock::new(None)),
        tls_config,
        request_log_tx: log_tx,
        event_log_tx: event_tx,
        body_dump_tx,
        http_client,
        probe_client,
        chatgpt_oauth,
        kiro_oauth,
        app_handle: handle.clone(),
    };

    // 8. 启动代理
    let proxy_state = state.clone();
    tauri::async_runtime::spawn(async move {
        if let Err(e) = proxy::server::start(proxy_state).await {
            error!(?e, "proxy server stopped");
        }
    });

    // 9. 启动订阅巡检器:每 10min 扫描被虚拟模型引用且异常的订阅, ping 通过则复活
    let recheck_state = state.clone();
    tauri::async_runtime::spawn(async move {
        subscription::recheck_worker::run(recheck_state).await;
    });

    let cleanup_pool = state.db.clone();
    let cleanup_settings = state.settings.clone();
    tauri::async_runtime::spawn(async move {
        observability::cleanup::run(cleanup_pool, cleanup_settings).await;
    });

    Ok(state)
}
