mod seeding;
use data_persistence_service as app;
use axum::Router;
use sqlx::PgPool;
use sqlx::migrate::MigrateError;
use tracing_subscriber::{EnvFilter, fmt::SubscriberBuilder};
use tower_http::trace::TraceLayer;

#[tokio::main]
pub async fn main() {
    dotenvy::dotenv().ok();
    app::load(); // This single function now ensures all handlers are linked.
    // 初始化 tracing 日志（默认 INFO，可通过 RUST_LOG 覆盖）
    let _ = SubscriberBuilder::default()
        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
        .with_target(true)
        .compact()
        .try_init();

    let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let pool = PgPool::connect(&db_url).await.expect("Failed to connect to database");

    // Run database migrations (strict by default; can be skipped via env for dev)
    let skip_migrations = std::env::var("SKIP_MIGRATIONS")
        .map(|v| {
            let v = v.to_ascii_lowercase();
            v == "1" || v == "true" || v == "yes" || v == "on"
        })
        .unwrap_or(false);
    if skip_migrations {
        println!("⚠️  SKIP_MIGRATIONS=1 → 跳过数据库迁移（仅建议用于本地开发/调试）。");
    } else {
        let res = sqlx::migrate!("./migrations").run(&pool).await;
        if let Err(e) = res {
            let allow_on_mismatch = std::env::var("SKIP_MIGRATIONS_ON_MISMATCH")
                .map(|v| {
                    let v = v.to_ascii_lowercase();
                    v == "1" || v == "true" || v == "yes" || v == "on"
                })
                .unwrap_or(false);
            match &e {
                MigrateError::VersionMismatch(ver) if allow_on_mismatch => {
                    eprintln!(
                        "❗ 检测到迁移版本不一致：VersionMismatch({}).\n\
                         已根据 SKIP_MIGRATIONS_ON_MISMATCH=1 跳过迁移运行，仅继续启动服务。\n\
                         建议修复：\n\
                         1) 不要修改已应用的迁移文件；如需变更，请创建新迁移；\n\
                         2) 或使用 `sqlx migrate repair` 修复校验；\n\
                         3) 或清空/重建数据库后重新应用迁移。",
                        ver
                    );
                }
                _ => {
                    panic!("Failed to run database migrations: {}", e);
                }
            }
        }
    }
    
    // Seed the database with default data if necessary
    if let Err(e) = seeding::seed_data(&pool).await {
        tracing::error!("Failed to seed database: {}", e);
        // We don't exit here, as the app might still be functional.
    }

    let state = app::AppState::new(pool);

    let openapi = app::build_openapi_spec();

    // 使用 RestRouterBuilder 并注入全局状态（通过内部 Any 保存，无需将 Router 设为带泛型状态）
    let rest: Router = app::build_rest_router_with_state(openapi.clone(), state.clone())
        .expect("build rest router");
    #[cfg(feature = "swagger-ui")]
    let swagger = app::build_swagger_ui(openapi.clone());
    #[cfg(feature = "wasm-cli")]
    let cli_assets = app::build_cli_assets_router();

    let mut app_router: Router = Router::new()
        .merge(rest)
        .layer(app::default_cors_layer())
        .layer(TraceLayer::new_for_http());

    #[cfg(feature = "swagger-ui")]
    {
        app_router = app_router.merge(swagger);
    }

    #[cfg(feature = "wasm-cli")]
    {
        app_router = app_router.merge(cli_assets);
    }

    #[cfg(feature = "mcp")]
    {
        let mcp = app::build_mcp_service(openapi.clone()).expect("build mcp service");
        app_router = app_router.nest_service("/mcp", mcp);
    }

    let address =
        std::env::var("HOST").unwrap_or_else(|_| "0.0.0.0".into()) + ":" + &std::env::var("PORT").unwrap_or_else(|_| "3000".into());
    println!("🚀 Server running at http://{}", address);
    println!("📚 Swagger UI available at http://{}/swagger-ui", address);
    println!("💻 Forge CLI UI available at http://{}/cli-ui", address);
    let skip_listen = std::env::var("SKIP_SERVER_LISTEN")
        .map(|v| {
            let v = v.to_ascii_lowercase();
            v == "1" || v == "true" || v == "yes" || v == "on"
        })
        .unwrap_or(false);
    if skip_listen {
        println!("🧪 SKIP_SERVER_LISTEN=1 → 跳过启动监听，仅用于测试/构建环境。");
        return;
    }
    let listener = tokio::net::TcpListener::bind(&address).await.unwrap();
    axum::serve(listener, app_router).await.unwrap();
}

