use clap::Parser;
use config::AppConfig;
use db::cache::AppCache;
use db::database::AppDatabase;
use git::hook::HookService;
use observability::init_tracing_subscriber;
use tokio::signal;

mod args;

use args::HookArgs;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 1. Load configuration
    let cfg = AppConfig::load();

    // 2. Init tracing logging
    let log_level = cfg.log_level().unwrap_or_else(|_| "info".to_string());
    init_tracing_subscriber(&log_level, false);

    // 3. Connect to database
    let db = AppDatabase::init(&cfg).await?;
    tracing::info!("database connected");

    // 4. Connect to Redis cache (also provides the cluster pool for hook queue)
    let cache = AppCache::init(&cfg).await?;
    tracing::info!("cache connected");

    // 5. Parse CLI args
    let _args = HookArgs::parse();

    tracing::info!("git-hook worker starting");

    // 6. Build and start git hook service
    let hooks = HookService::new(
        db,
        cache.clone(),
        cache.redis_pool().clone(),
        cfg,
    );

    let cancel = hooks.start_worker();
    let cancel_signal = cancel.clone();

    // Spawn signal handler that cancels on SIGINT/SIGTERM
    tokio::spawn(async move {
        let ctrl_c = async {
            signal::ctrl_c()
                .await
                .expect("failed to install CTRL+C handler");
        };

        #[cfg(unix)]
        let term = async {
            use tokio::signal::unix::{SignalKind, signal};
            let mut sig =
                signal(SignalKind::terminate()).expect("failed to install SIGTERM handler");
            sig.recv().await;
        };

        #[cfg(not(unix))]
        let term = std::future::pending::<()>();

        tokio::select! {
            _ = ctrl_c => {
                tracing::info!("received SIGINT, initiating shutdown");
            }
            _ = term => {
                tracing::info!("received SIGTERM, initiating shutdown");
            }
        }
        cancel_signal.cancel();
    });

    // Wait until the worker is cancelled (by signal handler or otherwise)
    cancel.cancelled().await;
    tracing::info!("git-hook worker stopped");
    Ok(())
}
