//! Filter preset handlers for saving and loading custom filters

use crate::error::{ApiError, ApiResult};
use crate::state::AppState;
use axum::{
    extract::{Path, State},
    http::StatusCode,
    Json,
};
use chrono::Utc;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// Create filter preset request
#[derive(Debug, Deserialize)]
pub struct CreatePresetRequest {
    /// Preset name
    pub name: String,
    /// User ID (in production, extracted from auth token)
    pub user_id: String,
    /// Filter configuration as JSON
    pub filters_json: String,
    /// Make this the default preset
    pub is_default: Option<bool>,
}

/// Filter preset DTO
#[derive(Debug, Serialize)]
pub struct FilterPresetDto {
    /// Preset ID
    pub id: String,
    /// User ID
    pub user_id: String,
    /// Preset name
    pub name: String,
    /// Filter configuration
    pub filters_json: String,
    /// Is default preset
    pub is_default: bool,
    /// Created timestamp
    pub created_at: String,
}

/// List all filter presets for a user
///
/// Retrieves all saved filter configurations for the authenticated user.
pub async fn list_presets(
    State(state): State<AppState>,
    Path(user_id): Path<String>,
) -> ApiResult<Json<Vec<FilterPresetDto>>> {
    // Verify user exists
    let _user = sqlx::query("SELECT id FROM users WHERE id = ?")
        .bind(&user_id)
        .fetch_optional(state.db.pool())
        .await
        .map_err(|e| ApiError::Database(e.to_string()))?
        .ok_or_else(|| ApiError::NotFound(format!("User {} not found", user_id)))?;

    // Fetch presets
    let presets: Vec<(String, String, String, String, bool, String)> = sqlx::query_as(
        r#"
        SELECT id, user_id, name, filters_json, is_default, created_at
        FROM filter_presets
        WHERE user_id = ?
        ORDER BY is_default DESC, created_at DESC
        "#,
    )
    .bind(&user_id)
    .fetch_all(state.db.pool())
    .await
    .map_err(|e| ApiError::Database(e.to_string()))?;

    let dtos = presets
        .into_iter()
        .map(
            |(id, user_id, name, filters_json, is_default, created_at)| FilterPresetDto {
                id,
                user_id,
                name,
                filters_json,
                is_default,
                created_at,
            },
        )
        .collect();

    Ok(Json(dtos))
}

/// Create a new filter preset
///
/// Saves a new filter configuration for quick access.
pub async fn create_preset(
    State(state): State<AppState>,
    Json(req): Json<CreatePresetRequest>,
) -> ApiResult<(StatusCode, Json<FilterPresetDto>)> {
    // Verify user exists
    let _user = sqlx::query("SELECT id FROM users WHERE id = ?")
        .bind(&req.user_id)
        .fetch_optional(state.db.pool())
        .await
        .map_err(|e| ApiError::Database(e.to_string()))?
        .ok_or_else(|| ApiError::NotFound(format!("User {} not found", req.user_id)))?;

    // Validate JSON format
    if serde_json::from_str::<serde_json::Value>(&req.filters_json).is_err() {
        return Err(ApiError::BadRequest(
            "Invalid JSON in filters_json".to_string(),
        ));
    }

    let preset_id = Uuid::new_v4().to_string();
    let now = Utc::now().to_rfc3339();
    let is_default = req.is_default.unwrap_or(false);

    // If setting as default, unset other defaults
    if is_default {
        sqlx::query("UPDATE filter_presets SET is_default = 0 WHERE user_id = ?")
            .bind(&req.user_id)
            .execute(state.db.pool())
            .await
            .map_err(|e| ApiError::Database(e.to_string()))?;
    }

    // Create preset
    sqlx::query(
        r#"
        INSERT INTO filter_presets (id, user_id, name, filters_json, is_default, created_at, updated_at)
        VALUES (?, ?, ?, ?, ?, ?, ?)
        "#
    )
    .bind(&preset_id)
    .bind(&req.user_id)
    .bind(&req.name)
    .bind(&req.filters_json)
    .bind(is_default)
    .bind(&now)
    .bind(&now)
    .execute(state.db.pool())
    .await
    .map_err(|e| ApiError::Database(e.to_string()))?;

    Ok((
        StatusCode::CREATED,
        Json(FilterPresetDto {
            id: preset_id,
            user_id: req.user_id,
            name: req.name,
            filters_json: req.filters_json,
            is_default,
            created_at: now,
        }),
    ))
}

/// Get a specific filter preset
///
/// Retrieves a filter preset by ID.
pub async fn get_preset(
    State(state): State<AppState>,
    Path((user_id, preset_id)): Path<(String, String)>,
) -> ApiResult<Json<FilterPresetDto>> {
    let preset: (String, String, String, String, bool, String) = sqlx::query_as(
        r#"
        SELECT id, user_id, name, filters_json, is_default, created_at
        FROM filter_presets
        WHERE id = ? AND user_id = ?
        "#,
    )
    .bind(&preset_id)
    .bind(&user_id)
    .fetch_optional(state.db.pool())
    .await
    .map_err(|e| ApiError::Database(e.to_string()))?
    .ok_or_else(|| ApiError::NotFound(format!("Preset {} not found", preset_id)))?;

    Ok(Json(FilterPresetDto {
        id: preset.0,
        user_id: preset.1,
        name: preset.2,
        filters_json: preset.3,
        is_default: preset.4,
        created_at: preset.5,
    }))
}

/// Delete a filter preset
///
/// Removes a saved filter configuration.
pub async fn delete_preset(
    State(state): State<AppState>,
    Path((user_id, preset_id)): Path<(String, String)>,
) -> ApiResult<StatusCode> {
    let result = sqlx::query("DELETE FROM filter_presets WHERE id = ? AND user_id = ?")
        .bind(&preset_id)
        .bind(&user_id)
        .execute(state.db.pool())
        .await
        .map_err(|e| ApiError::Database(e.to_string()))?;

    if result.rows_affected() == 0 {
        return Err(ApiError::NotFound(format!(
            "Preset {} not found",
            preset_id
        )));
    }

    Ok(StatusCode::NO_CONTENT)
}

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

    #[test]
    fn test_create_preset_request() {
        let json = r#"{
            "name": "High Priority Tasks",
            "user_id": "user-123",
            "filters_json": "{\"priority\":\"high\",\"status\":\"pending\"}",
            "is_default": true
        }"#;
        let req: CreatePresetRequest = serde_json::from_str(json).unwrap();

        assert_eq!(req.name, "High Priority Tasks");
        assert_eq!(req.is_default, Some(true));
    }

    #[test]
    fn test_filter_preset_dto_serialization() {
        let dto = FilterPresetDto {
            id: "preset-1".to_string(),
            user_id: "user-1".to_string(),
            name: "My Filters".to_string(),
            filters_json: r#"{"status":"active"}"#.to_string(),
            is_default: false,
            created_at: "2025-01-01T00:00:00Z".to_string(),
        };

        let json = serde_json::to_string(&dto).unwrap();
        assert!(json.contains("My Filters"));
        assert!(json.contains("status"));
    }
}
