use chrono::{prelude::*, Duration};
// use once_cell::sync::Lazy;
use sqlx::{postgres::PgPoolOptions, PgPool, Pool, Postgres};
use std::env;

mod tasks;

pub struct TaskManager<'a> {
    pool: Pool<Postgres>,
    jobs: Vec<TaskJob>,
    last_activated: Option<chrono::DateTime<Utc>>,
    last_job: Option<TaskJob>,
    scheduler: job_scheduler::JobScheduler<'a>,
}

pub struct TaskLog {
    task_log_id: u8,
    task_id: u8,
    created_at: chrono::DateTime<Utc>,
    task_status: TaskStatus,
}

enum TaskStatus {
    Pending,
    Completed,
    Failed,
}

#[derive(Debug, sqlx::FromRow)]
pub struct TaskJob {
    pub task_id: i32,
    pub task_name: String,
    pub schedule: String,
    pub is_active: bool,
    pub created_at: chrono::DateTime<Utc>,
    pub deleted_at: Option<chrono::DateTime<Utc>>,
}

#[tokio::main]
async fn main() {
    println!("Hello, world!");

    dotenvy::dotenv().unwrap();
    let database_url =
        env::var("DATABASE_URL").expect("Environment variable DATABASE_URL is not found");
    let pool = PgPoolOptions::new()
        .max_connections(10)
        .connect(&database_url)
        .await
        .expect("Failed to connect to the database");

    let mut manager = TaskManager::new(pool);
    manager.register_jobs().await;

    loop {
        manager.scheduler.tick();
        std::thread::sleep(std::time::Duration::from_millis(1000));
    }
}

impl<'a> TaskManager<'a> {
    fn new(pool: Pool<Postgres>) -> Self {
        TaskManager {
            pool,
            jobs: Vec::new(),
            last_activated: None,
            last_job: None,
            scheduler: job_scheduler::JobScheduler::new(),
        }
    }

    pub async fn register_jobs(&self) {
        // let jobs: Vec<Job> = Vec::new();
        let results = sqlx::query_as::<_, TaskJob>("SELECT task_id, task_name, schedule, is_active, created_at, deleted_at FROM tasks WHERE is_active = true AND deleted_at IS NULL")
            .fetch_all(&self.pool)
            .await
            .unwrap();

        let mut scheduler = job_scheduler::JobScheduler::new();
        results
            .iter()
            .map(|j| {
                scheduler.add(job_scheduler::Job::new(j.schedule.parse().unwrap(), || {
                    println!("Starting task name: {:?}", j.task_name);

                    match j.task_id {
                        1 => tasks::import_posts::import_posts("/app", &self.pool),
                        _ => panic!(),
                    }
                }));
            })
            .collect::<Vec<_>>();
    }
}