//! Burndown analytics and progress tracking handlers

use crate::error::{ApiError, ApiResult};
use crate::models::{BurndownData, ProjectStats};
use crate::state::AppState;
use axum::{
    extract::{Path, State},
    Json,
};
use chrono::Utc;
use std::collections::BTreeMap;
use syntaxis_core::persistence::Database;

/// Get burndown chart data for a project
pub(crate) async fn burndown_data(
    State(state): State<AppState>,
    Path(project_id): Path<String>,
) -> ApiResult<Json<BurndownData>> {
    // Verify project exists
    let _project = state
        .db
        .get_project(&project_id)
        .await?
        .ok_or_else(|| ApiError::NotFound(format!("Project {} not found", project_id)))?;

    let tasks = state.db.get_checklist_items(&project_id).await?;

    let total = tasks.len() as f64;
    let completed = tasks.iter().filter(|t| t.completed).count() as f64;

    // Group completion history by date
    let mut daily_data: BTreeMap<String, u32> = BTreeMap::new();
    for task in &tasks {
        if let Some(completed_at) = &task.completed_at {
            // Extract date part (YYYY-MM-DD)
            if let Some(date) = completed_at.split('T').next() {
                *daily_data.entry(date.to_string()).or_insert(0) += 1;
            }
        }
    }

    // Calculate ideal vs actual burndown
    let mut ideal = Vec::new();
    let mut actual = Vec::new();
    let mut dates = Vec::new();
    let mut cumulative = 0.0;

    // Assume 14-day sprint
    let sprint_days = 14.0;
    let ideal_per_day = total / sprint_days;

    // Generate burndown data
    for (i, (date, count)) in daily_data.iter().enumerate() {
        dates.push(date.clone());
        ideal.push(total - (i as f64 * ideal_per_day));
        cumulative += *count as f64;
        actual.push(total - cumulative);
    }

    // If no completion data, provide basic structure
    if dates.is_empty() {
        dates.push(Utc::now().format("%Y-%m-%d").to_string());
        ideal.push(total);
        actual.push(total);
    }

    Ok(Json(BurndownData {
        dates,
        ideal,
        actual,
        total_tasks: tasks.len() as u32,
        completed_tasks: completed as u32,
    }))
}

/// Get project progress statistics
pub(crate) async fn progress_stats(
    State(state): State<AppState>,
    Path(project_id): Path<String>,
) -> ApiResult<Json<ProjectStats>> {
    // Verify project exists
    let _project = state
        .db
        .get_project(&project_id)
        .await?
        .ok_or_else(|| ApiError::NotFound(format!("Project {} not found", project_id)))?;

    let tasks = state.db.get_checklist_items(&project_id).await?;

    let total = tasks.len();
    let completed = tasks.iter().filter(|t| t.completed).count();
    let pending = total - completed;
    let percent = if total > 0 {
        (completed as f64 / total as f64) * 100.0
    } else {
        0.0
    };

    // Milestones not yet implemented in Database trait
    let milestone_percent = 0.0;
    let total_milestones = 0;

    Ok(Json(ProjectStats {
        total_tasks: total,
        completed_tasks: completed,
        pending_tasks: pending,
        completion_percent: percent,
        milestone_percent,
        total_milestones,
    }))
}

/// Get velocity metrics (tasks completed per day)
pub(crate) async fn velocity_data(
    State(state): State<AppState>,
    Path(project_id): Path<String>,
) -> ApiResult<Json<serde_json::Value>> {
    // Verify project exists
    let _project = state
        .db
        .get_project(&project_id)
        .await?
        .ok_or_else(|| ApiError::NotFound(format!("Project {} not found", project_id)))?;

    let tasks = state.db.get_checklist_items(&project_id).await?;

    // Calculate velocity by week
    let mut weekly_velocity: BTreeMap<String, u32> = BTreeMap::new();

    for task in &tasks {
        if let Some(completed_at) = &task.completed_at {
            // Extract week from ISO 8601 timestamp (YYYY-W##)
            if completed_at.len() >= 7 {
                let year_week = format!(
                    "{}-W{:02}",
                    &completed_at[..4],                             // Year
                    completed_at[6..8].parse::<u32>().unwrap_or(1)  // Week
                );
                *weekly_velocity.entry(year_week).or_insert(0) += 1;
            }
        }
    }

    let weeks: Vec<String> = weekly_velocity.keys().cloned().collect();
    let counts: Vec<u32> = weekly_velocity.values().copied().collect();

    let avg_velocity = if !counts.is_empty() {
        counts.iter().sum::<u32>() as f64 / counts.len() as f64
    } else {
        0.0
    };

    Ok(Json(serde_json::json!({
        "weeks": weeks,
        "velocity": counts,
        "average_velocity": avg_velocity,
    })))
}
