use axum::{
    extract::{Path, State},
    response::Json,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;

use crate::{
    db::{ExternalCalendar, ExternalCalendarRepository},
    models::ApiError,
    AppState,
};

use super::auth::{extract_bearer_token};

#[derive(Debug, Deserialize)]
pub struct CreateExternalCalendarRequest {
    pub name: String,
    pub url: String,
    pub color: String,
}

#[derive(Debug, Deserialize)]
pub struct UpdateExternalCalendarRequest {
    pub name: String,
    pub url: String,
    pub color: String,
    pub is_visible: bool,
}

#[derive(Debug, Serialize)]
pub struct ExternalCalendarResponse {
    pub id: i32,
    pub name: String,
    pub url: String,
    pub color: String,
    pub is_visible: bool,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
    pub last_fetched: Option<chrono::DateTime<chrono::Utc>>,
}

impl From<ExternalCalendar> for ExternalCalendarResponse {
    fn from(calendar: ExternalCalendar) -> Self {
        Self {
            id: calendar.id,
            name: calendar.name,
            url: calendar.url,
            color: calendar.color,
            is_visible: calendar.is_visible,
            created_at: calendar.created_at,
            updated_at: calendar.updated_at,
            last_fetched: calendar.last_fetched,
        }
    }
}

pub async fn get_external_calendars(
    headers: axum::http::HeaderMap,
    State(app_state): State<Arc<AppState>>,
) -> Result<Json<Vec<ExternalCalendarResponse>>, ApiError> {
    // Extract and verify token, get user
    let token = extract_bearer_token(&headers)?;
    let user = app_state.auth_service.get_user_from_token(&token).await?;

    let repo = ExternalCalendarRepository::new(&app_state.db);
    let calendars = repo
        .get_by_user(&user.id)
        .await
        .map_err(|e| ApiError::Database(format!("Failed to get external calendars: {}", e)))?;

    let response: Vec<ExternalCalendarResponse> = calendars.into_iter().map(Into::into).collect();
    Ok(Json(response))
}

pub async fn create_external_calendar(
    headers: axum::http::HeaderMap,
    State(app_state): State<Arc<AppState>>,
    Json(request): Json<CreateExternalCalendarRequest>,
) -> Result<Json<ExternalCalendarResponse>, ApiError> {
    let token = extract_bearer_token(&headers)?;
    let user = app_state.auth_service.get_user_from_token(&token).await?;

    let calendar = ExternalCalendar::new(
        user.id,
        request.name,
        request.url,
        request.color,
    );

    let repo = ExternalCalendarRepository::new(&app_state.db);
    let id = repo
        .create(&calendar)
        .await
        .map_err(|e| ApiError::Database(format!("Failed to create external calendar: {}", e)))?;

    let mut created_calendar = calendar;
    created_calendar.id = id;

    Ok(Json(created_calendar.into()))
}

pub async fn update_external_calendar(
    headers: axum::http::HeaderMap,
    State(app_state): State<Arc<AppState>>,
    Path(id): Path<i32>,
    Json(request): Json<UpdateExternalCalendarRequest>,
) -> Result<Json<()>, ApiError> {
    let token = extract_bearer_token(&headers)?;
    let user = app_state.auth_service.get_user_from_token(&token).await?;

    let mut calendar = ExternalCalendar::new(
        user.id,
        request.name,
        request.url,
        request.color,
    );
    calendar.is_visible = request.is_visible;

    let repo = ExternalCalendarRepository::new(&app_state.db);
    repo.update(id, &calendar)
        .await
        .map_err(|e| ApiError::Database(format!("Failed to update external calendar: {}", e)))?;

    Ok(Json(()))
}

pub async fn delete_external_calendar(
    headers: axum::http::HeaderMap,
    State(app_state): State<Arc<AppState>>,
    Path(id): Path<i32>,
) -> Result<Json<()>, ApiError> {
    let token = extract_bearer_token(&headers)?;
    let user = app_state.auth_service.get_user_from_token(&token).await?;

    let repo = ExternalCalendarRepository::new(&app_state.db);
    repo.delete(id, &user.id)
        .await
        .map_err(|e| ApiError::Database(format!("Failed to delete external calendar: {}", e)))?;

    Ok(Json(()))
}