use actix_web::middleware::from_fn;
use actix_web::{App, HttpServer, web};
use tracing::{error, info};
use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod};
use reqwest::Client;
use sqlx::postgres::PgPool;
use std::pin::Pin;

mod auth;
mod config;
mod db;
mod error;
mod handlers;
mod models;
mod rate_limiter;

use auth::jwt_middleware;
use config::AppConfig;
use db::create_pool;
use handlers::{
    admin_get_user, admin_update_user_payment, add_favorite, alipay_notify, alipay_pay_page,
    create_order, delete_weather, generate_code, generate_temp_token_handler, get_current_user_profile,
    get_favorites, get_user_quota, get_weather_brief, get_weather_details,
    get_user_orders, health_check, login, mock_login, mock_confirm, sync_order, payment_index, payment_login_status, payment_page, payment_success,
    post_weather_data,
    refresh_token, remove_favorite, root, save_user_profile, serve_static_files,
    web_generate_login_code, web_login_confirm, web_login_auto_confirm,
};
use models::AppState;

// 加载TLS证书和私钥
fn create_ssl_acceptor() -> Result<SslAcceptorBuilder, Box<dyn std::error::Error>> {
    let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;

    // 从环境变量获取证书和私钥路径
    let key_path =
        std::env::var("SSL_KEY_PATH").unwrap_or_else(|_| "path/to/private.key".to_string());
    let cert_path =
        std::env::var("SSL_CERT_PATH").unwrap_or_else(|_| "path/to/certificate.crt".to_string());

    builder.set_private_key_file(&key_path, SslFiletype::PEM)?;
    builder.set_certificate_chain_file(&cert_path)?;

    // 返回构建器
    Ok(builder)
}

fn create_server_config(
    pool: PgPool,
    http_client: Client,
    app_state: AppState,
) -> App<
    impl actix_web::dev::ServiceFactory<
        actix_web::dev::ServiceRequest,
        Config = (),
        Response = actix_web::dev::ServiceResponse,
        Error = actix_web::Error,
        InitError = (),
    >,
> {
    App::new()
        .app_data(web::Data::new(pool))
        .app_data(web::Data::new(http_client))
        .app_data(web::Data::new(app_state))
        // 根路径（无需认证）
        .service(root) // #[get("/")] - 返回服务信息
        // 支付页面（无需认证，外部浏览器访问）
        .service(payment_index)  // GET /payment — 套餐选择页
        .service(generate_code)   // GET /payment/generate-code — 网页生成登录码
        .service(payment_page)  // GET /payment/page（需 JWT）
        .service(payment_success)
        .service(alipay_pay_page) // GET /payment/pay（需 JWT）
        .service(alipay_notify)   // POST /payment/notify（支付宝异步回调）
        .service(payment_login_status) // GET /payment/login-status（网页轮询）
        // 静态文件（无需认证）
        .service(web::resource("/static/{tail:.*}").route(web::get().to(serve_static_files)))
        // API 接口
        .service(login)  // #[post("/api/login")]
        .service(mock_login)  // #[get("/api/mock-login")]（沙箱测试用）
        .service(refresh_token) // #[post("/api/refresh-token")]（公开接口，无需认证）
        .service(get_weather_details) // #[get("/weather/details")]（支持 JWT 或 temp_token，公开接口）
        .service(health_check)
        .service(web_generate_login_code)
        .service(web_login_confirm)
        .service(web_login_auto_confirm)
        .service(
            web::scope("")
                .wrap(from_fn(jwt_middleware))
                .service(post_weather_data)
                .service(get_weather_brief)
                .service(generate_temp_token_handler)
                .service(delete_weather)
                .service(get_current_user_profile)
                .service(save_user_profile)
                .service(admin_get_user)
                .service(admin_update_user_payment)
                .service(create_order)
                .service(mock_confirm)
                .service(sync_order)
                .service(get_user_orders)
                .service(get_user_quota)
                .service(get_favorites)
                .service(add_favorite)
                .service(remove_favorite)
        )
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // 加载配置文件（支持多环境）
    let app_config = match AppConfig::load() {
        Ok(cfg) => cfg,
        Err(e) => {
            eprintln!("配置加载失败: {}", e);
            std::process::exit(1);
        }
    };

    // 设置环境变量（向后兼容依赖 env var 的组件）
    unsafe {
        std::env::set_var("DATABASE_URL", &app_config.database_url);
        std::env::set_var("JWT_SECRET", &app_config.jwt_secret);
        std::env::set_var("WECHAT_APPID", &app_config.wechat_appid);
        std::env::set_var("WECHAT_SECRET", &app_config.wechat_secret);
        std::env::set_var("SSL_KEY_PATH", &app_config.ssl_key_path);
        std::env::set_var("SSL_CERT_PATH", &app_config.ssl_cert_path);
        std::env::set_var("RUST_LOG", &app_config.rust_log);
        std::env::set_var("FREE_USER_DATA_LIMIT", app_config.free_user_data_limit.to_string());
    }

    // 初始化文件日志（JSON 格式，带轮转）
    let log_dir = std::path::Path::new("./logs");
    std::fs::create_dir_all(log_dir).ok(); // 确保日志目录存在

    let file_appender = tracing_appender::rolling::Builder::new()
        .rotation(tracing_appender::rolling::Rotation::DAILY)
        .filename_prefix("rust-backend")
        .filename_suffix("log")
        .build(log_dir)
        .expect("无法创建日志文件");

    let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);

    // 保持文件 guard 存活（使用 Box 泄漏）
    std::mem::forget(_guard);

    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::from_default_env()
                .add_directive(format!("rust_backend={}", app_config.rust_log).parse().unwrap())
                .add_directive(format!("actix_web={}", app_config.rust_log).parse().unwrap())
                .add_directive("sqlx=warn".parse().unwrap())
        )
        .with_target(true)
        .with_thread_ids(false) // 生产环境可开启
        .with_file(true)
        .with_line_number(true)
        .with_writer(non_blocking)
        .with_ansi(false) // 文件中不使用 ANSI 颜色
        .json() // JSON 格式便于 ELK 解析
        .init();
    info!("日志系统初始化成功，JSON格式，输出到 ./logs/");

    let app_state = match AppState::load() {
        Ok(state) => state,
        Err(e) => {
            error!("环境变量配置错误: {}", e);
            std::process::exit(1);
        }
    };

    let pool = match create_pool().await {
        Ok(pool) => pool,
        Err(e) => {
            error!("Failed to create database pool: {}", e);
            error!("Please check your database connection configuration in .env file");
            std::process::exit(1);
        }
    };

    let http_client = Client::new();

    info!("Attempting to start server...");

    let is_production = std::env::var("APP_ENV").unwrap_or_else(|_| "development".into()) == "production";
    let ports = if is_production {
        vec![4433, 8443, 8080, 3000, 8000, 8888]
    } else {
        vec![8080, 3000, 8000, 8888, 4433, 8443]
    };
    let mut server: Option<
        Pin<Box<dyn std::future::Future<Output = std::io::Result<()>> + Unpin>>,
    > = None;
    let mut bound_port = 0;

    for port in &ports {
        let addr = format!("127.0.0.1:{}", port);
        info!("Trying to bind to {}", addr);

        let pool_clone = pool.clone();
        let http_client_clone = http_client.clone();
        let app_state_clone = app_state.clone();

        if *port == 443 || *port == 8443 || *port == 4433 {
            let ssl_builder = match create_ssl_acceptor() {
                Ok(builder) => builder,
                Err(e) => {
                    error!("Failed to create SSL acceptor: {}", e);
                    continue;
                }
            };

            match HttpServer::new(move || {
                create_server_config(pool_clone.clone(), http_client_clone.clone(), app_state_clone.clone())
            })
            .bind_openssl(&addr, ssl_builder)
            {
                Ok(s) => {
                    info!("Successfully bound to {} with HTTPS", addr);
                    let server_future = s.run();
                    server = Some(Box::pin(server_future));
                    bound_port = *port;
                    break;
                }
                Err(e) => {
                    error!("Failed to bind to {} with HTTPS: {}", addr, e);
                    if e.kind() == std::io::ErrorKind::PermissionDenied {
                        error!("  -> Permission denied. Try running with sudo or use a port > 1024");
                    }
                    continue;
                }
            }
        } else {
            match HttpServer::new(move || {
                create_server_config(pool_clone.clone(), http_client_clone.clone(), app_state_clone.clone())
            })
            .bind(&addr)
            {
                Ok(s) => {
                    info!("Successfully bound to {} with HTTP", addr);
                    let server_future = s.run();
                    server = Some(Box::pin(server_future));
                    bound_port = *port;
                    break;
                }
                Err(e) => {
                    error!("Failed to bind to {} with HTTP: {}", addr, e);
                    if e.kind() == std::io::ErrorKind::PermissionDenied {
                        error!(
                            "  -> Permission denied. Try running with sudo or use a port > 1024"
                        );
                    }
                    continue;
                }
            }
        }
    }

    match server {
        Some(s) => {
            if bound_port == 443 || bound_port == 8443 {
                info!("Server started successfully with HTTPS");
            } else {
                info!("Server started successfully with HTTP");
            }
            s.await
        }
        None => {
            error!("Failed to bind to any port. Please check your system configuration.");
            std::process::exit(1);
        }
    }
}
