use axum::{
    http::StatusCode,
    response::{IntoResponse, Response},
    Json,
};
use calendar_models::VAlarm;
use serde::{Deserialize, Serialize};

// API request/response types
#[derive(Debug, Deserialize)]
pub struct CalDAVLoginRequest {
    pub username: String,
    pub password: String,
    pub server_url: String,
}

#[derive(Debug, Serialize)]
pub struct AuthResponse {
    pub token: String,
    pub session_token: String,
    pub username: String,
    pub server_url: String,
    pub preferences: UserPreferencesResponse,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct UserPreferencesResponse {
    pub calendar_selected_date: Option<String>,
    pub calendar_time_increment: Option<i32>,
    pub calendar_view_mode: Option<String>,
    pub calendar_theme: Option<String>,
    pub calendar_style: Option<String>,
    pub calendar_colors: Option<String>,
    pub last_used_calendar: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct UpdatePreferencesRequest {
    pub calendar_selected_date: Option<String>,
    pub calendar_time_increment: Option<i32>,
    pub calendar_view_mode: Option<String>,
    pub calendar_theme: Option<String>,
    pub calendar_style: Option<String>,
    pub calendar_colors: Option<String>,
    pub last_used_calendar: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct UserInfo {
    pub username: String,
    pub server_url: String,
    pub calendars: Vec<CalendarInfo>,
}

#[derive(Debug, Serialize)]
pub struct CalendarInfo {
    pub path: String,
    pub display_name: String,
    pub color: String,
    pub is_visible: bool,
}

#[derive(Debug, Deserialize)]
pub struct CreateCalendarRequest {
    pub name: String,
    pub description: Option<String>,
    pub color: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct CreateCalendarResponse {
    pub success: bool,
    pub message: String,
}

#[derive(Debug, Deserialize)]
pub struct DeleteCalendarRequest {
    pub path: String,
}

#[derive(Debug, Serialize)]
pub struct DeleteCalendarResponse {
    pub success: bool,
    pub message: String,
}

#[derive(Debug, Deserialize)]
pub struct DeleteEventRequest {
    pub calendar_path: String,
    pub event_href: String,
    pub delete_action: String, // "delete_this", "delete_following", or "delete_series"
    pub occurrence_date: Option<String>, // ISO date string for the specific occurrence
}

#[derive(Debug, Serialize)]
pub struct DeleteEventResponse {
    pub success: bool,
    pub message: String,
}

#[derive(Debug, Deserialize)]
pub struct CreateEventRequest {
    pub title: String,
    pub description: String,
    pub start_date: String, // YYYY-MM-DD format
    pub start_time: String, // HH:MM format
    pub end_date: String,   // YYYY-MM-DD format
    pub end_time: String,   // HH:MM format
    pub location: String,
    pub all_day: bool,
    pub status: String,                // confirmed, tentative, cancelled
    pub class: String,                 // public, private, confidential
    pub priority: Option<u8>,          // 0-9 priority level
    pub organizer: String,             // organizer email
    pub attendees: String,             // comma-separated attendee emails
    pub categories: String,            // comma-separated categories
    pub alarms: Vec<VAlarm>,           // event alarms
    pub recurrence: String,            // recurrence type
    pub recurrence_days: Vec<bool>,    // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] for weekly recurrence
    pub calendar_path: Option<String>, // Optional - use first calendar if not specified
    pub timezone: String,              // Client timezone (e.g., "+05:00", "-04:00")
}

#[derive(Debug, Serialize)]
pub struct CreateEventResponse {
    pub success: bool,
    pub message: String,
    pub event_href: Option<String>, // The created event's href/filename
}

#[derive(Debug, Deserialize)]
pub struct UpdateEventRequest {
    pub uid: String, // Event UID to identify which event to update
    pub title: String,
    pub description: String,
    pub start_date: String, // YYYY-MM-DD format
    pub start_time: String, // HH:MM format
    pub end_date: String,   // YYYY-MM-DD format
    pub end_time: String,   // HH:MM format
    pub location: String,
    pub all_day: bool,
    pub status: String,                // confirmed, tentative, cancelled
    pub class: String,                 // public, private, confidential
    pub priority: Option<u8>,          // 0-9 priority level
    pub organizer: String,             // organizer email
    pub attendees: String,             // comma-separated attendee emails
    pub categories: String,            // comma-separated categories
    pub alarms: Vec<VAlarm>,           // event alarms
    pub recurrence: String,            // recurrence type
    pub recurrence_days: Vec<bool>,    // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] for weekly recurrence
    pub recurrence_interval: Option<u32>, // Every N days/weeks/months/years
    pub recurrence_count: Option<u32>, // Number of occurrences
    pub recurrence_end_date: Option<String>, // When the series ends (YYYY-MM-DD)
    pub calendar_path: Option<String>, // Optional - search all calendars if not specified
    pub update_action: Option<String>, // "update_series" for recurring events
    pub timezone: String,              // Client timezone (e.g., "+05:00", "-04:00")
    #[serde(skip_serializing_if = "Option::is_none")]
    pub until_date: Option<String>, // ISO datetime string for RRULE UNTIL clause
}

#[derive(Debug, Serialize)]
pub struct UpdateEventResponse {
    pub success: bool,
    pub message: String,
}

// ==================== EVENT SERIES MODELS ====================

#[derive(Debug, Deserialize)]
pub struct CreateEventSeriesRequest {
    pub title: String,
    pub description: String,
    pub start_date: String, // YYYY-MM-DD format
    pub start_time: String, // HH:MM format
    pub end_date: String,   // YYYY-MM-DD format
    pub end_time: String,   // HH:MM format
    pub location: String,
    pub all_day: bool,
    pub status: String,       // confirmed, tentative, cancelled
    pub class: String,        // public, private, confidential
    pub priority: Option<u8>, // 0-9 priority level
    pub organizer: String,    // organizer email
    pub attendees: String,    // comma-separated attendee emails
    pub categories: String,   // comma-separated categories
    pub alarms: Vec<VAlarm>,  // event alarms

    // Series-specific fields
    pub recurrence: String, // recurrence type (daily, weekly, monthly, yearly)
    pub recurrence_days: Vec<bool>, // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] for weekly recurrence
    pub recurrence_interval: Option<u32>, // Every N days/weeks/months/years
    pub recurrence_end_date: Option<String>, // When the series ends (YYYY-MM-DD)
    pub recurrence_count: Option<u32>, // Number of occurrences
    pub calendar_path: Option<String>, // Optional - search all calendars if not specified
    pub timezone: String,              // Client timezone (e.g., "+05:00", "-04:00")
}

#[derive(Debug, Serialize)]
pub struct CreateEventSeriesResponse {
    pub success: bool,
    pub message: String,
    pub series_uid: Option<String>, // The base UID for the series
    pub occurrences_created: Option<u32>, // Number of individual events created
    pub event_href: Option<String>, // The created series' href/filename
}

#[derive(Debug, Deserialize)]
pub struct UpdateEventSeriesRequest {
    pub series_uid: String, // Series UID to identify which series to update
    pub title: String,
    pub description: String,
    pub start_date: String, // YYYY-MM-DD format
    pub start_time: String, // HH:MM format
    pub end_date: String,   // YYYY-MM-DD format
    pub end_time: String,   // HH:MM format
    pub location: String,
    pub all_day: bool,
    pub status: String,       // confirmed, tentative, cancelled
    pub class: String,        // public, private, confidential
    pub priority: Option<u8>, // 0-9 priority level
    pub organizer: String,    // organizer email
    pub attendees: String,    // comma-separated attendee emails
    pub categories: String,   // comma-separated categories
    pub alarms: Vec<VAlarm>,  // event alarms

    // Series-specific fields
    pub recurrence: String, // recurrence type (daily, weekly, monthly, yearly)
    pub recurrence_days: Vec<bool>, // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] for weekly recurrence
    pub recurrence_interval: Option<u32>, // Every N days/weeks/months/years
    pub recurrence_end_date: Option<String>, // When the series ends (YYYY-MM-DD)
    pub recurrence_count: Option<u32>, // Number of occurrences
    pub calendar_path: Option<String>, // Optional - search all calendars if not specified

    // Update scope control
    pub update_scope: String, // "this_only", "this_and_future", "all_in_series"
    pub occurrence_date: Option<String>, // ISO date string for specific occurrence being updated
    pub changed_fields: Option<Vec<String>>, // List of field names that were changed (for optimization)
    pub timezone: String,              // Client timezone (e.g., "+05:00", "-04:00")
}

#[derive(Debug, Serialize)]
pub struct UpdateEventSeriesResponse {
    pub success: bool,
    pub message: String,
    pub series_uid: Option<String>,
    pub occurrences_affected: Option<u32>, // Number of events updated
}

#[derive(Debug, Deserialize)]
pub struct DeleteEventSeriesRequest {
    pub series_uid: String, // Series UID to identify which series to delete
    pub calendar_path: String,
    pub event_href: String,

    // Delete scope control
    pub delete_scope: String, // "this_only", "this_and_future", "all_in_series"
    pub occurrence_date: Option<String>, // ISO date string for specific occurrence being deleted
}

#[derive(Debug, Serialize)]
pub struct DeleteEventSeriesResponse {
    pub success: bool,
    pub message: String,
    pub occurrences_affected: Option<u32>, // Number of events deleted
}

// Error handling
#[derive(Debug)]
pub enum ApiError {
    Database(String),
    NotFound(String),
    Unauthorized(String),
    BadRequest(String),
    Conflict(String),
    Internal(String),
}

impl IntoResponse for ApiError {
    fn into_response(self) -> Response {
        let (status, error_message) = match self {
            ApiError::Database(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
            ApiError::NotFound(msg) => (StatusCode::NOT_FOUND, msg),
            ApiError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, msg),
            ApiError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
            ApiError::Conflict(msg) => (StatusCode::CONFLICT, msg),
            ApiError::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
        };

        let body = Json(serde_json::json!({
            "error": error_message,
            "status": status.as_u16()
        }));

        (status, body).into_response()
    }
}

impl std::fmt::Display for ApiError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ApiError::Database(msg) => write!(f, "Database error: {}", msg),
            ApiError::NotFound(msg) => write!(f, "Not found: {}", msg),
            ApiError::Unauthorized(msg) => write!(f, "Unauthorized: {}", msg),
            ApiError::BadRequest(msg) => write!(f, "Bad request: {}", msg),
            ApiError::Conflict(msg) => write!(f, "Conflict: {}", msg),
            ApiError::Internal(msg) => write!(f, "Internal error: {}", msg),
        }
    }
}

impl std::error::Error for ApiError {}
