mod context;
mod health;
mod shutdown;

use context::AppContext;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let ctx = AppContext::init().await?;

    tracing::info!("gitsync service starting");

    let health_port = ctx.config.gitsync_health_port();
    let health_server =
        health::start_health(health_port, ctx.db.clone(), ctx.cache.clone())?;
    let health_handle = health_server.handle();
    let health_task = tokio::spawn(health_server);

    let sync_service =
        git::sync::ReceiveSyncService::new(ctx.redis_pool.clone());
    let consumer = git::sync::consumer::SyncConsumer::new(sync_service, 5);
    let worker = git::sync::worker::SyncWorker::new(
        consumer,
        ctx.db.clone(),
        ctx.cache.clone(),
        ctx.redis_pool.clone(),
        ctx.config.clone(),
        format!("gitsync-{}", uuid::Uuid::new_v4()),
    );

    let worker_task = tokio::spawn(async move { worker.run().await });

    tokio::select! {
        result = health_task => {
            match result {
                Ok(Ok(())) => tracing::info!("health server stopped"),
                Ok(Err(e)) => tracing::error!("health server error: {}", e),
                Err(e) => tracing::error!("health task panicked: {}", e),
            }
        }
        _ = worker_task => {
            tracing::info!("sync worker stopped");
        }
        _ = shutdown::wait_for_shutdown_signal() => {
            tracing::info!("shutdown signal received, stopping gitsync service");
            health_handle.stop(true).await;
        }
    }

    Ok(())
}
