use crate::error::{ApiError, Result};
use crate::models::{EventV2, PendingEventV2, CreateEventRequestV2, SubmitEventRequestV2, ApiResponse, PaginatedResponse};
use crate::utils::{
    response::success_response,
    pagination::PaginationHelper,
    datetime::{parse_datetime_with_timezone, DEFAULT_CHURCH_TIMEZONE},
    validation::{ValidationBuilder, validate_recurring_type},
    urls::UrlBuilder,
    common::ListQueryParams,
    converters::{convert_events_to_v2, convert_event_to_v2},
    db_operations::EventOperations,
};
use axum::{
    extract::{Path, Query, State, Multipart},
    Json,
};
use uuid::Uuid;
use chrono::{Datelike, Timelike};
use crate::{db, AppState};

// Use shared ListQueryParams instead of custom EventQuery
// #[derive(Deserialize)]
// pub struct EventQuery {
//     page: Option<i32>,
//     per_page: Option<i32>,
//     timezone: Option<String>,
// }

pub async fn list(
    State(state): State<AppState>,
    Query(query): Query<ListQueryParams>,
) -> Result<Json<ApiResponse<PaginatedResponse<EventV2>>>> {
    let timezone = query.timezone.as_deref().unwrap_or(DEFAULT_CHURCH_TIMEZONE);
    let pagination = PaginationHelper::from_query(query.page, query.per_page);
    
    let events = crate::db::events::list(&state.pool).await?;
    let total = events.len() as i64;
    
    // Apply pagination
    let start = pagination.offset as usize;
    let end = std::cmp::min(start + pagination.per_page as usize, events.len());
    let paginated_events = if start < events.len() {
        events[start..end].to_vec()
    } else {
        Vec::new()
    };
    
    // Convert to V2 format using shared converter
    let url_builder = UrlBuilder::new();
    let events_v2 = convert_events_to_v2(paginated_events, timezone, &url_builder)?;
    
    let response = pagination.create_response(events_v2, total);
    Ok(success_response(response))
}

pub async fn get_upcoming(
    State(state): State<AppState>,
    Query(query): Query<ListQueryParams>,
) -> Result<Json<ApiResponse<Vec<EventV2>>>> {
    let timezone = query.timezone.as_deref().unwrap_or(DEFAULT_CHURCH_TIMEZONE);
    let events = EventOperations::get_upcoming(&state.pool, 50).await?;
    let url_builder = UrlBuilder::new();
    let events_v2 = convert_events_to_v2(events, timezone, &url_builder)?;
    Ok(success_response(events_v2))
}

pub async fn get_featured(
    State(state): State<AppState>,
    Query(query): Query<ListQueryParams>,
) -> Result<Json<ApiResponse<Vec<EventV2>>>> {
    let timezone = query.timezone.as_deref().unwrap_or(DEFAULT_CHURCH_TIMEZONE);
    let events = EventOperations::get_featured(&state.pool, 10).await?;
    let url_builder = UrlBuilder::new();
    let events_v2 = convert_events_to_v2(events, timezone, &url_builder)?;
    Ok(success_response(events_v2))
}

pub async fn get_by_id(
    State(state): State<AppState>,
    Path(id): Path<Uuid>,
    Query(query): Query<ListQueryParams>,
) -> Result<Json<ApiResponse<EventV2>>> {
    let timezone = query.timezone.as_deref().unwrap_or(DEFAULT_CHURCH_TIMEZONE);
    let event = crate::db::events::get_by_id(&state.pool, &id).await?
        .ok_or_else(|| ApiError::NotFound("Event not found".to_string()))?;
    
    let url_builder = UrlBuilder::new();
    let event_v2 = convert_event_to_v2(event, timezone, &url_builder)?;
    Ok(success_response(event_v2))
}

pub async fn create(
    State(state): State<AppState>,
    Json(req): Json<CreateEventRequestV2>,
) -> Result<Json<ApiResponse<EventV2>>> {
    let timezone = req.timezone.as_deref().unwrap_or(DEFAULT_CHURCH_TIMEZONE);
    
    ValidationBuilder::new()
        .require(&req.title, "title")
        .require(&req.description, "description")
        .require(&req.location, "location")
        .require(&req.category, "category")
        .validate_length(&req.title, "title", 1, 255)
        .validate_length(&req.description, "description", 1, 2000)
        .validate_url(&req.location_url.as_deref().unwrap_or(""), "location_url")
        .validate_timezone(timezone)
        .build()?;
    
    validate_recurring_type(&req.recurring_type)?;
    
    let start_time = parse_datetime_with_timezone(&req.start_time, Some(timezone))?;
    let end_time = parse_datetime_with_timezone(&req.end_time, Some(timezone))?;
    
    if end_time.utc <= start_time.utc {
        return Err(ApiError::ValidationError("End time must be after start time".to_string()));
    }
    
    let event_id = Uuid::new_v4();
    let event = db::events::create(&state.pool, &event_id, &crate::models::CreateEventRequest {
        title: req.title,
        description: req.description,
        start_time: start_time.utc,
        end_time: end_time.utc,
        location: req.location,
        location_url: req.location_url,
        category: req.category,
        is_featured: req.is_featured,
        recurring_type: req.recurring_type,
    }).await?;
    
    let url_builder = UrlBuilder::new();
    let event_v2 = convert_event_to_v2(event, timezone, &url_builder)?;
    
    Ok(success_response(event_v2))
}

pub async fn submit(
    State(state): State<AppState>,
    mut multipart: Multipart,
) -> Result<Json<ApiResponse<String>>> {
    let mut req_data = SubmitEventRequestV2 {
        title: String::new(),
        description: String::new(),
        start_time: String::new(),
        end_time: String::new(),
        location: String::new(),
        location_url: None,
        category: String::new(),
        is_featured: None,
        recurring_type: None,
        bulletin_week: String::new(),
        submitter_email: None,
        timezone: None,
    };
    
    let mut image_data: Option<Vec<u8>> = None;
    
    while let Some(field) = multipart.next_field().await
        .map_err(|e| ApiError::ValidationError(format!("Failed to read multipart field: {}", e)))? {
        
        let name = field.name()
            .ok_or_else(|| ApiError::ValidationError("Field name is required".to_string()))?;
        
        match name {
            "title" => req_data.title = field.text().await
                .map_err(|e| ApiError::ValidationError(format!("Failed to read title: {}", e)))?,
            "description" => req_data.description = field.text().await
                .map_err(|e| ApiError::ValidationError(format!("Failed to read description: {}", e)))?,
            "start_time" => req_data.start_time = field.text().await
                .map_err(|e| ApiError::ValidationError(format!("Failed to read start_time: {}", e)))?,
            "end_time" => req_data.end_time = field.text().await
                .map_err(|e| ApiError::ValidationError(format!("Failed to read end_time: {}", e)))?,
            "location" => req_data.location = field.text().await
                .map_err(|e| ApiError::ValidationError(format!("Failed to read location: {}", e)))?,
            "location_url" => {
                let url = field.text().await
                    .map_err(|e| ApiError::ValidationError(format!("Failed to read location_url: {}", e)))?;
                req_data.location_url = if url.is_empty() { None } else { Some(url) };
            },
            "category" => req_data.category = field.text().await
                .map_err(|e| ApiError::ValidationError(format!("Failed to read category: {}", e)))?,
            "bulletin_week" => req_data.bulletin_week = field.text().await
                .map_err(|e| ApiError::ValidationError(format!("Failed to read bulletin_week: {}", e)))?,
            "submitter_email" => {
                let email = field.text().await
                    .map_err(|e| ApiError::ValidationError(format!("Failed to read submitter_email: {}", e)))?;
                req_data.submitter_email = if email.is_empty() { None } else { Some(email) };
            },
            "timezone" => {
                let tz = field.text().await
                    .map_err(|e| ApiError::ValidationError(format!("Failed to read timezone: {}", e)))?;
                req_data.timezone = if tz.is_empty() { None } else { Some(tz) };
            },
            "image" => {
                if field.file_name().is_some() {
                    image_data = Some(field.bytes().await
                        .map_err(|e| ApiError::ValidationError(format!("Failed to read image data: {}", e)))?
                        .to_vec());
                }
            },
            _ => {
                // Skip unknown fields
            }
        }
    }
    
    let timezone = req_data.timezone.as_deref().unwrap_or(DEFAULT_CHURCH_TIMEZONE);
    
    // Auto-determine bulletin_week based on submission time
    // Before Friday 00:00 UTC (Thursday 7pm EST) = "current", after = "next"
    let now = chrono::Utc::now();
    let current_weekday = now.weekday();
    let current_hour = now.hour();
    
    req_data.bulletin_week = match current_weekday {
        chrono::Weekday::Mon | chrono::Weekday::Tue | chrono::Weekday::Wed | chrono::Weekday::Thu => "current".to_string(),
        chrono::Weekday::Fri if current_hour == 0 => "current".to_string(),
        _ => "next".to_string(),
    };
    
    ValidationBuilder::new()
        .require(&req_data.title, "title")
        .require(&req_data.description, "description")
        .require(&req_data.location, "location")
        .require(&req_data.category, "category")
        .validate_length(&req_data.title, "title", 1, 255)
        .validate_length(&req_data.description, "description", 1, 2000)
        .validate_url(&req_data.location_url.as_deref().unwrap_or(""), "location_url")
        .validate_timezone(timezone)
        .build()?;
    
    if let Some(email) = &req_data.submitter_email {
        ValidationBuilder::new().validate_email(email).build()?;
    }
    
    validate_recurring_type(&req_data.recurring_type)?;
    
    let start_time = parse_datetime_with_timezone(&req_data.start_time, Some(timezone))?;
    let end_time = parse_datetime_with_timezone(&req_data.end_time, Some(timezone))?;
    
    if end_time.utc <= start_time.utc {
        return Err(ApiError::ValidationError("End time must be after start time".to_string()));
    }
    
    let event_id = Uuid::new_v4();
    let submit_request = crate::models::SubmitEventRequest {
        title: req_data.title,
        description: req_data.description,
        start_time: start_time.utc,
        end_time: end_time.utc,
        location: req_data.location,
        location_url: req_data.location_url,
        category: req_data.category,
        is_featured: req_data.is_featured,
        recurring_type: req_data.recurring_type,
        bulletin_week: req_data.bulletin_week,
        submitter_email: req_data.submitter_email,
        image: None,
        thumbnail: None,
    };
    
    let _pending_event = db::events::submit(&state.pool, &event_id, &submit_request).await?;
    
    if let Some(image_bytes) = image_data {
        let image_path = format!("uploads/pending_events/{}_image.webp", event_id);
        
        let state_clone = state.clone();
        let event_id_clone = event_id;
        crate::utils::tasks::spawn_with_error_handling("process_event_image", async move {
            let converted_image = crate::utils::images::convert_to_webp(&image_bytes)?;
            tokio::fs::write(&image_path, converted_image).await
                .map_err(|e| ApiError::Internal(format!("Failed to save image: {}", e)))?;
            
            db::events::update_pending_image(&state_clone.pool, &event_id_clone, &image_path).await?;
            Ok(())
        });
    }
    
    Ok(success_response("Event submitted successfully and is pending approval".to_string()))
}

// Converter functions moved to shared utils/converters.rs module

pub async fn list_pending(
    State(state): State<AppState>,
    Query(query): Query<ListQueryParams>,
) -> Result<Json<ApiResponse<PaginatedResponse<PendingEventV2>>>> {
    let pagination = PaginationHelper::from_query(query.page, query.per_page);
    let timezone = query.timezone.as_deref().unwrap_or(DEFAULT_CHURCH_TIMEZONE);
    
    let events = db::events::list_pending(&state.pool, pagination.page, pagination.per_page).await?;
    let total = db::events::count_pending(&state.pool).await?;
    
    let mut events_v2 = Vec::new();
    let url_builder = UrlBuilder::new();
    
    for event in events {
        let event_v2 = crate::utils::converters::convert_pending_event_to_v2(event, timezone, &url_builder)?;
        events_v2.push(event_v2);
    }
    
    let response = pagination.create_response(events_v2, total);
    Ok(success_response(response))
}