use std::sync::Arc;

use axum::{
    extract::{Query, State},
    http::{header, StatusCode},
    response::{IntoResponse, Response},
    routing::get,
    Json, Router,
};
use serde::{Deserialize, Serialize};

use crate::db::{maps, stats, wipes};
use crate::middleware::auth::AuthUser;
use crate::models::error::{ApiError, ApiResult};
use crate::AppState;

pub fn router() -> Router<Arc<AppState>> {
    Router::new()
        .route("/summary", get(get_summary))
        .route("/timeseries", get(get_timeseries))
        .route("/export", get(export_csv))
        .route("/wipes/performance", get(get_wipe_performance))
}

/// Query parameters for analytics endpoints.
#[derive(Debug, Deserialize)]
struct AnalyticsQuery {
    /// Time range in hours (default: 24)
    #[serde(default = "default_range")]
    range: i64,
    /// Granularity: "raw" or "hourly" (default: "hourly")
    #[serde(default = "default_granularity")]
    granularity: String,
}

fn default_range() -> i64 {
    24
}

fn default_granularity() -> String {
    "hourly".to_string()
}

/// GET /api/analytics/summary?range=7d
/// Returns peak players, avg players, uptime percentage.
async fn get_summary(
    auth: AuthUser,
    State(state): State<Arc<AppState>>,
    Query(query): Query<AnalyticsQuery>,
) -> ApiResult<Json<stats::AnalyticsSummary>> {
    let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;

    let summary = stats::get_analytics_summary(&state.db, license_id, query.range)
        .await
        .map_err(|e| ApiError::Internal(e.to_string()))?;

    Ok(Json(summary))
}

/// GET /api/analytics/timeseries?range=24&granularity=hourly
/// Returns time-series data for charting.
#[derive(Serialize)]
struct TimeseriesResponse {
    timestamps: Vec<String>,
    player_count: Vec<i32>,
    fps: Vec<f64>,
    entity_count: Vec<i32>,
    memory_usage_mb: Vec<i32>,
}

async fn get_timeseries(
    auth: AuthUser,
    State(state): State<Arc<AppState>>,
    Query(query): Query<AnalyticsQuery>,
) -> ApiResult<Json<TimeseriesResponse>> {
    let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;

    if query.granularity == "hourly" {
        // Use hourly aggregates
        let hourly_stats = stats::get_hourly_stats(&state.db, license_id, query.range)
            .await
            .map_err(|e| ApiError::Internal(e.to_string()))?;

        let timestamps: Vec<String> = hourly_stats
            .iter()
            .map(|s| s.hour.to_rfc3339())
            .collect();

        let player_count: Vec<i32> = hourly_stats
            .iter()
            .map(|s| s.max_players)
            .collect();

        let fps: Vec<f64> = hourly_stats
            .iter()
            .map(|s| s.avg_fps)
            .collect();

        let entity_count: Vec<i32> = hourly_stats
            .iter()
            .map(|s| s.avg_entities)
            .collect();

        // Hourly stats don't track memory, return zeros
        let memory_usage_mb: Vec<i32> = vec![0; hourly_stats.len()];

        Ok(Json(TimeseriesResponse {
            timestamps,
            player_count,
            fps,
            entity_count,
            memory_usage_mb,
        }))
    } else {
        // Use raw stats (default limit: 1000 samples)
        let limit = (query.range * 60).min(1000); // 1 sample per minute, max 1000
        let raw_stats = stats::get_recent_stats(&state.db, license_id, limit)
            .await
            .map_err(|e| ApiError::Internal(e.to_string()))?;

        let timestamps: Vec<String> = raw_stats
            .iter()
            .map(|s| s.recorded_at.to_rfc3339())
            .collect();

        let player_count: Vec<i32> = raw_stats
            .iter()
            .map(|s| s.player_count)
            .collect();

        let fps: Vec<f64> = raw_stats
            .iter()
            .map(|s| s.fps)
            .collect();

        let entity_count: Vec<i32> = raw_stats
            .iter()
            .map(|s| s.entity_count)
            .collect();

        let memory_usage_mb: Vec<i32> = raw_stats
            .iter()
            .map(|s| s.memory_usage_mb)
            .collect();

        Ok(Json(TimeseriesResponse {
            timestamps,
            player_count,
            fps,
            entity_count,
            memory_usage_mb,
        }))
    }
}

/// GET /api/analytics/export?range=168
/// Export stats as CSV.
async fn export_csv(
    auth: AuthUser,
    State(state): State<Arc<AppState>>,
    Query(query): Query<AnalyticsQuery>,
) -> Result<Response, ApiError> {
    let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;

    // Get raw stats for CSV export
    let limit = (query.range * 60).min(10000); // Max 10k rows
    let raw_stats = stats::get_recent_stats(&state.db, license_id, limit)
        .await
        .map_err(|e| ApiError::Internal(e.to_string()))?;

    // Build CSV
    let mut csv = String::from("timestamp,player_count,max_players,fps,entity_count,uptime_seconds,memory_usage_mb\n");
    for stat in raw_stats.iter().rev() {
        // Reverse to chronological order
        csv.push_str(&format!(
            "{},{},{},{:.2},{},{},{}\n",
            stat.recorded_at.to_rfc3339(),
            stat.player_count,
            stat.max_players,
            stat.fps,
            stat.entity_count,
            stat.uptime_seconds,
            stat.memory_usage_mb
        ));
    }

    // Return CSV response
    Ok((
        StatusCode::OK,
        [
            (header::CONTENT_TYPE, "text/csv"),
            (
                header::CONTENT_DISPOSITION,
                "attachment; filename=\"server_stats.csv\"",
            ),
        ],
        csv,
    )
        .into_response())
}

// ========================================================================
// WIPE ANALYTICS — Phase 2
// ========================================================================

/// Query parameters for wipe analytics.
#[derive(Debug, Deserialize)]
struct WipeAnalyticsQuery {
    /// Time range in days (default: 90)
    #[serde(default = "default_wipe_range")]
    range: String,
}

fn default_wipe_range() -> String {
    "90d".to_string()
}

/// Response for wipe performance analytics.
#[derive(Debug, Serialize)]
struct WipePerformanceResponse {
    total_wipes: i64,
    successful_wipes: i64,
    failed_wipes: i64,
    success_rate_percent: f64,
    avg_duration_seconds: f64,
    wipes: Vec<wipes::WipeAnalyticsEntry>,
    population_curve: wipes::PopulationCurve,
    optimal_wipe_day: String,
    optimal_wipe_hour: i32,
}

/// GET /api/analytics/wipes/performance?range=90d
/// Returns wipe performance metrics: success rate, duration, population curves, optimal timing.
async fn get_wipe_performance(
    auth: AuthUser,
    State(state): State<Arc<AppState>>,
    Query(query): Query<WipeAnalyticsQuery>,
) -> ApiResult<Json<WipePerformanceResponse>> {
    let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;

    // Parse range string (e.g., "90d", "30d", "all")
    let days = parse_wipe_range(&query.range);

    // Query analytics
    let (total_wipes, successful_wipes, failed_wipes) =
        wipes::get_wipe_success_rate(&state.db, license_id, days)
            .await
            .map_err(|e| ApiError::Internal(e.to_string()))?;

    let avg_duration_seconds = wipes::get_average_wipe_duration(&state.db, license_id, days)
        .await
        .map_err(|e| ApiError::Internal(e.to_string()))?;

    let population_curve = wipes::get_population_curve_by_cycle(&state.db, license_id, days)
        .await
        .map_err(|e| ApiError::Internal(e.to_string()))?;

    let optimal_timing = wipes::get_optimal_wipe_timing(&state.db, license_id, days)
        .await
        .map_err(|e| ApiError::Internal(e.to_string()))?;

    let wipe_entries = wipes::get_wipe_analytics_entries(&state.db, license_id, days)
        .await
        .map_err(|e| ApiError::Internal(e.to_string()))?;

    let success_rate_percent = if total_wipes > 0 {
        (successful_wipes as f64 / total_wipes as f64) * 100.0
    } else {
        0.0
    };

    Ok(Json(WipePerformanceResponse {
        total_wipes,
        successful_wipes,
        failed_wipes,
        success_rate_percent,
        avg_duration_seconds,
        wipes: wipe_entries,
        population_curve,
        optimal_wipe_day: optimal_timing.optimal_wipe_day,
        optimal_wipe_hour: optimal_timing.optimal_wipe_hour,
    }))
}

/// Parse wipe range string to days.
fn parse_wipe_range(range: &str) -> i64 {
    if range == "all" {
        365 * 10 // 10 years = effectively all
    } else if let Some(days_str) = range.strip_suffix('d') {
        days_str.parse::<i64>().unwrap_or(90)
    } else {
        90 // Default to 90 days
    }
}

