//! 充电柜矩阵系统 — 后端入口

mod config;
mod db;
mod error;
mod middleware;
mod redis;
mod routes;
mod tcp;

use std::net::SocketAddr;
use tracing_subscriber::EnvFilter;

use tcp::commands::AppState;
use tcp::connection::ConnectionPool;

#[tokio::main]
async fn main() {
    // 初始化日志
    tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
        .init();

    // 加载配置
    let cfg = config::Config::from_env();
    cfg.validate();
    tracing::info!("配置加载完成");

    // 初始化 MySQL 连接池
    let db_pool = db::init_pool(&cfg.database_url)
        .await
        .expect("MySQL 连接失败");
    tracing::info!("数据库连接成功");

    // 执行自动迁移
    db::migrate::run(&db_pool)
        .await
        .expect("数据库迁移失败");
    tracing::info!("数据库迁移完成");

    // 初始化 Redis 连接（ConnectionManager 内部管理重连，可直接 Clone 共享）
    let redis_conn = redis::init_connection(&cfg.redis_url)
        .await
        .expect("Redis 连接失败");
    tracing::info!("Redis 连接成功");

    // 初始化设备连接池
    let device_pool = ConnectionPool::new();

    // 构建共享状态
    let state = AppState {
        device_pool: device_pool.clone(),
        redis: redis_conn.clone(),
        mysql: db_pool.clone(),
    };

    // 启动 TCP 设备服务（后台）
    let tcp_addr = format!("{}:{}", cfg.host, cfg.tcp_port);
    tracing::info!("TCP 设备服务启动于 {}", tcp_addr);
    let tcp_pool = device_pool.clone();
    let tcp_redis = redis_conn.clone();
    let tcp_mysql = db_pool.clone();
    tokio::spawn(async move {
        tcp::run_tcp_server(tcp_addr, tcp_pool, tcp_redis, tcp_mysql).await;
    });

    // 构建 HTTP 路由（包含设备指令下发端点和认证中间件）
    let app = routes::build(state);

    // 启动 HTTP 服务
    let addr: SocketAddr = format!("{}:{}", cfg.host, cfg.port)
        .parse()
        .expect("无效的监听地址");
    tracing::info!("HTTP 服务器启动于 http://{}", addr);

    let listener = tokio::net::TcpListener::bind(addr)
        .await
        .expect("端口绑定失败");
    axum::serve(listener, app)
        .await
        .expect("服务器运行失败");
}
