// retrigger-build-marker-2
#![allow(dead_code)]

use std::env;
use std::sync::Arc;
use std::time::Duration;
use sqlx::postgres::PgPoolOptions;
use tokio::time;

mod tasks;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt::init();
    tracing::info!("Starting NXTGAUGE Cron Expiry Engine...");

    let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let pool = PgPoolOptions::new()
        .max_connections(10)
        .connect(&db_url)
        .await?;

    let mailer = Arc::new(email::Mailer::new());

    // Spawn 15-minute lead request expiry task
    let p_lead_sys = pool.clone();
    let m_lead_sys = Arc::clone(&mailer);
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(15 * 60));
        loop {
            interval.tick().await;
            tracing::info!("Running Lead Request Expiry Task...");
            if let Err(e) = tasks::leads::expire_stale_lead_requests(&p_lead_sys, &m_lead_sys).await {
                tracing::error!("Lead Expiry Task Failed: {}", e);
            }
        }
    });

    // Spawn Hourly Lead expiry task
    let p_req_sys = pool.clone();
    let m_req_sys = Arc::clone(&mailer);
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(60 * 60));
        loop {
            interval.tick().await;
            tracing::info!("Running Lead Expiry Task...");
            if let Err(e) = tasks::requirements::expire_stale_leads(&p_req_sys, &m_req_sys).await {
                tracing::error!("Lead Expiry Task Failed: {}", e);
            }
        }
    });

    // Spawn Hourly Job Expiry task
    let p_job_sys = pool.clone();
    let m_job_sys = Arc::clone(&mailer);
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(60 * 60));
        loop {
            interval.tick().await;
            tracing::info!("Running Job Expiry Task...");
            if let Err(e) = tasks::jobs::expire_stale_jobs(&p_job_sys, &m_job_sys).await {
                tracing::error!("Job Expiry Task Failed: {}", e);
            }
        }
    });

    // Spawn Daily Reminder task
    let p_rem_sys = pool.clone();
    let m_rem_sys = Arc::clone(&mailer);
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(24 * 60 * 60));
        loop {
            interval.tick().await;
            tracing::info!("Running Daily Reminders Task...");
            if let Err(e) = tasks::reminders::send_expiry_reminders(&p_rem_sys, &m_rem_sys).await {
                tracing::error!("Reminders Task Failed: {}", e);
            }
        }
    });

    // Spawn AI credits reservation-hold reaper (every 2 minutes -- holds
    // expire after 5 minutes by default, so this catches abandoned holds
    // promptly without hammering the wallet table).
    let p_ai_reap = pool.clone();
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(2 * 60));
        loop {
            interval.tick().await;
            if let Err(e) = tasks::ai_credits::sweep_expired_reservation_holds(&p_ai_reap).await {
                tracing::error!("AI Credit Reservation Reaper Failed: {}", e);
            }
        }
    });

    // Spawn AI credits daily-usage-counter reset (hourly -- idempotent
    // no-op for any wallet whose counters are already current; exists so
    // admin-facing "today's usage" is accurate even for untouched wallets,
    // not because charge-path correctness depends on it).
    let p_ai_reset = pool.clone();
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(60 * 60));
        loop {
            interval.tick().await;
            if let Err(e) = tasks::ai_credits::reset_stale_daily_ai_usage(&p_ai_reset).await {
                tracing::error!("AI Credit Daily Usage Reset Failed: {}", e);
            }
        }
    });

    // Spawn AI credits subscription lifecycle tasks (hourly)
    // Task 7: Apply scheduled downgrades and expire trials
    let p_ai_sub = pool.clone();
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(60 * 60));
        loop {
            interval.tick().await;
            if let Err(e) = tasks::ai_credits::apply_scheduled_downgrades(&p_ai_sub).await {
                tracing::error!("AI Credit Scheduled Downgrades Failed: {}", e);
            }
            if let Err(e) = tasks::ai_credits::expire_trials(&p_ai_sub).await {
                tracing::error!("AI Credit Trial Expiry Failed: {}", e);
            }
        }
    });

    // Spawn AI credits purchased credit expiration (daily)
    // Task 8: Expire purchased credits past their expiration date
    let p_ai_expiry = pool.clone();
    tokio::spawn(async move {
        let mut interval = time::interval(Duration::from_secs(24 * 60 * 60));
        loop {
            interval.tick().await;
            if let Err(e) = tasks::ai_credits::expire_purchased_credits(&p_ai_expiry).await {
                tracing::error!("AI Credit Purchased Credits Expiry Failed: {}", e);
            }
        }
    });

    // Keep main thread alive
    tokio::signal::ctrl_c().await?;
    tracing::info!("Shutting down cron engine.");

    Ok(())
}
