//! Recurring tasks background worker

use chrono::{DateTime, Utc};
use std::sync::Arc;
use syntaxis_core::SqliteDatabase;
use tokio::time::Duration;
use uuid::Uuid;

/// Recurrence rule for tasks
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct RecurrenceRule {
    /// Frequency: "daily", "weekly", "monthly"
    pub frequency: String,
    /// Interval (e.g., every 2 days, every 3 weeks)
    pub interval: u32,
    /// Optional end date
    pub end_date: Option<String>,
}

/// Recurring tasks background worker
///
/// Checks every hour for recurring tasks that need new instances created
pub async fn recurring_tasks_worker(db: Arc<SqliteDatabase>) {
    let mut interval = tokio::time::interval(Duration::from_secs(3600)); // Check hourly

    loop {
        interval.tick().await;

        match process_recurring_tasks(&db).await {
            Ok(count) => {
                if count > 0 {
                    tracing::info!("Created {} recurring task instances", count);
                }
            }
            Err(e) => {
                tracing::error!("Error in recurring tasks worker: {}", e);
            }
        }
    }
}

/// Process all recurring tasks and create new instances if needed
async fn process_recurring_tasks(db: &SqliteDatabase) -> Result<usize, Box<dyn std::error::Error>> {
    // Query all tasks with recurrence rules (using direct SQL since there's no recurrence_rule field in DbChecklistItem)
    let rows: Vec<(String, String, String, String, String, Option<String>)> = sqlx::query_as(
        "SELECT id, project_id, task_id, description, created_at, recurrence_rule
         FROM checklist_items WHERE recurrence_rule IS NOT NULL",
    )
    .fetch_all(db.pool())
    .await?;

    let mut created_count = 0;

    for (id, project_id, task_id, description, created_at, recurrence_rule) in rows {
        if let Some(rule_json) = recurrence_rule {
            match serde_json::from_str::<RecurrenceRule>(&rule_json) {
                Ok(rule) => {
                    if should_create_next_instance(&created_at, &rule)? {
                        create_task_instance(db, &project_id, &task_id, &description, &rule_json)
                            .await?;
                        created_count += 1;
                        tracing::debug!("Created recurring instance for task {}", id);
                    }
                }
                Err(e) => {
                    tracing::warn!("Failed to parse recurrence rule for task {}: {}", id, e);
                }
            }
        }
    }

    Ok(created_count)
}

/// Check if a new instance should be created based on recurrence rule
fn should_create_next_instance(
    last_created: &str,
    rule: &RecurrenceRule,
) -> Result<bool, Box<dyn std::error::Error>> {
    let now = Utc::now();

    // Check if we've passed the end date
    if let Some(end_date_str) = &rule.end_date {
        let end_date = DateTime::parse_from_rfc3339(end_date_str)?;
        if now > end_date {
            return Ok(false);
        }
    }

    let last_dt = DateTime::parse_from_rfc3339(last_created)?;
    let duration = now.signed_duration_since(last_dt);

    match rule.frequency.as_str() {
        "daily" => {
            let days_threshold = rule.interval as i64;
            Ok(duration.num_days() >= days_threshold)
        }
        "weekly" => {
            let weeks_threshold = rule.interval as i64;
            Ok(duration.num_weeks() >= weeks_threshold)
        }
        "monthly" => {
            // Approximate: 30 days per month
            let days_threshold = rule.interval as i64 * 30;
            Ok(duration.num_days() >= days_threshold)
        }
        _ => {
            tracing::warn!("Unknown recurrence frequency: {}", rule.frequency);
            Ok(false)
        }
    }
}

/// Create a new task instance from a recurring template
async fn create_task_instance(
    db: &SqliteDatabase,
    project_id: &str,
    task_id_base: &str,
    description: &str,
    recurrence_rule: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let new_id = Uuid::new_v4().to_string();
    let now = Utc::now().to_rfc3339();

    sqlx::query(
        "INSERT INTO checklist_items (id, project_id, phase, task_id, description, completed, created_at, recurrence_rule)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
    )
    .bind(&new_id)
    .bind(project_id)
    .bind("Creation")
    .bind(task_id_base)
    .bind(description)
    .bind(false)
    .bind(&now)
    .bind(recurrence_rule)
    .execute(db.pool())
    .await?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_should_create_daily() {
        let rule = RecurrenceRule {
            frequency: "daily".to_string(),
            interval: 1,
            end_date: None,
        };

        // Task created 2 days ago should trigger
        let two_days_ago = (Utc::now() - chrono::Duration::days(2)).to_rfc3339();
        assert!(should_create_next_instance(&two_days_ago, &rule).unwrap());

        // Task created 1 hour ago should not trigger
        let one_hour_ago = (Utc::now() - chrono::Duration::hours(1)).to_rfc3339();
        assert!(!should_create_next_instance(&one_hour_ago, &rule).unwrap());
    }

    #[test]
    fn test_should_create_weekly() {
        let rule = RecurrenceRule {
            frequency: "weekly".to_string(),
            interval: 1,
            end_date: None,
        };

        // Task created 8 days ago should trigger
        let eight_days_ago = (Utc::now() - chrono::Duration::days(8)).to_rfc3339();
        assert!(should_create_next_instance(&eight_days_ago, &rule).unwrap());

        // Task created 3 days ago should not trigger
        let three_days_ago = (Utc::now() - chrono::Duration::days(3)).to_rfc3339();
        assert!(!should_create_next_instance(&three_days_ago, &rule).unwrap());
    }

    #[test]
    fn test_end_date_respected() {
        let yesterday = (Utc::now() - chrono::Duration::days(1)).to_rfc3339();

        let rule = RecurrenceRule {
            frequency: "daily".to_string(),
            interval: 1,
            end_date: Some(yesterday),
        };

        let old_date = (Utc::now() - chrono::Duration::days(10)).to_rfc3339();
        assert!(!should_create_next_instance(&old_date, &rule).unwrap());
    }

    #[tokio::test]
    #[allow(unused_variables)]
    async fn test_recurring_task_creation() {
        // NOTE: Recurrence rule functionality not yet in Database trait
        // This test is templated for when recurrence support is added
        let db = SqliteDatabase::new(":memory:").await.unwrap();

        // When implemented, will test:
        // 1. Create project and recurring task template
        // 2. Process recurring tasks (create new instances based on rule)
        // 3. Verify new instances were created
        // Currently requires direct sqlx::query access which is not exposed via trait
    }
}
