use crate::error::ApiError;
use crate::models::{PaginationParams, CreateEventRequest};
use axum::{
    extract::{Path, Query, State},
    Json,
};
use serde::Deserialize;
use uuid::Uuid;

// New imports for WebP and multipart support
use axum::extract::Multipart;
use crate::utils::images::convert_to_webp;
use tokio::fs;
use chrono::{DateTime, Utc};

use crate::{
    db,
    error::Result,
    models::{Event, PendingEvent, SubmitEventRequest, ApiResponse, PaginatedResponse},
    AppState,
};

#[derive(Deserialize)]
pub struct EventQuery {
    page: Option<i32>,
    per_page: Option<i32>,
}

pub async fn list(
    State(state): State<AppState>,
    Query(_query): Query<EventQuery>,
) -> Result<Json<ApiResponse<PaginatedResponse<Event>>>> {
    let events = db::events::list(&state.pool).await?;
    let total = events.len() as i64;
    
    let response = PaginatedResponse {
        items: events,
        total,
        page: 1,
        per_page: 50,
        has_more: false,
    };

    Ok(Json(ApiResponse {
        success: true,
        data: Some(response),
        message: None,
    }))
}

pub async fn submit(
    State(state): State<AppState>,
    mut multipart: Multipart,
) -> Result<Json<ApiResponse<PendingEvent>>> {
    // Initialize the request struct with ACTUAL fields
    let mut req = SubmitEventRequest {
        title: String::new(),
        description: String::new(),
        start_time: Utc::now(), // Temporary default
        end_time: Utc::now(),   // Temporary default  
        location: String::new(),
        location_url: None,
        category: String::new(),
        is_featured: None,
        recurring_type: None,
        bulletin_week: String::new(),
        submitter_email: None,
        image: None,
	thumbnail: None,
    };

    // Track image paths (we'll save these separately to DB)
    let mut thumbnail_path: Option<String> = None;

    // Extract form fields and files
    while let Some(field) = multipart.next_field().await.map_err(|e| {
        ApiError::ValidationError(format!("Failed to read multipart field: {}", e))
    })? {
        let name = field.name().unwrap_or("").to_string();
        
        match name.as_str() {
            "title" => {
                req.title = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid title: {}", e))
                })?;
            },
            "description" => {
                req.description = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid description: {}", e))
                })?;
            },
            "start_time" => {
                let time_str = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid start_time: {}", e))
                })?;
                
                // Parse as NaiveDateTime first, then convert to UTC
                let naive_dt = chrono::NaiveDateTime::parse_from_str(&time_str, "%Y-%m-%dT%H:%M")
                    .map_err(|e| ApiError::ValidationError(format!("Invalid start_time format: {}", e)))?;
                req.start_time = DateTime::from_naive_utc_and_offset(naive_dt, Utc);
            },
            "end_time" => {
                let time_str = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid end_time: {}", e))
                })?;
                
                let naive_dt = chrono::NaiveDateTime::parse_from_str(&time_str, "%Y-%m-%dT%H:%M")
                    .map_err(|e| ApiError::ValidationError(format!("Invalid end_time format: {}", e)))?;
                req.end_time = DateTime::from_naive_utc_and_offset(naive_dt, Utc);
            },
            "location" => {
                req.location = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid location: {}", e))
                })?;
            },
            "category" => {
                req.category = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid category: {}", e))
                })?;
            },
            "location_url" => {
                let url = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid location_url: {}", e))
                })?;
                if !url.is_empty() {
                    req.location_url = Some(url);
                }
            },
            "reoccuring" => { // Note: form uses "reoccuring" but model uses "recurring_type"
                let recurring = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid recurring: {}", e))
                })?;
                if !recurring.is_empty() {
                    req.recurring_type = Some(recurring);
                }
            },
            "submitter_email" => {
                let email = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid submitter_email: {}", e))
                })?;
                if !email.is_empty() {
                    req.submitter_email = Some(email);
                }
            },
            "bulletin_week" => {
                req.bulletin_week = field.text().await.map_err(|e| {
                    ApiError::ValidationError(format!("Invalid bulletin_week: {}", e))
                })?;
            },
            "image" => {
                let image_data = field.bytes().await.map_err(|e| {
                    ApiError::ValidationError(format!("Failed to read image: {}", e))
                })?;
                
                if !image_data.is_empty() {
                    // Save original immediately
                    let uuid = Uuid::new_v4();
                    let original_path = format!("uploads/events/original_{}.jpg", uuid);
                    
                    // Ensure directory exists
                    fs::create_dir_all("uploads/events").await.map_err(|e| {
                        ApiError::FileError(e)
                    })?;
                    
                    fs::write(&original_path, &image_data).await.map_err(|e| {
                        ApiError::FileError(e)
                    })?;
                    
                    // Set original path immediately
                    
                    // Convert to WebP in background (user doesn't wait)
                    let pool = state.pool.clone();
                    tokio::spawn(async move {
                        if let Ok(webp_data) = convert_to_webp(&image_data).await {
                            let webp_path = format!("uploads/events/{}.webp", uuid);
                            if fs::write(&webp_path, webp_data).await.is_ok() {
                                // Update database with WebP path (using actual column name "image")
                               	    let full_url = format!("https://api.rockvilletollandsda.church/{}", webp_path);
				    let _ = sqlx::query!(
                                    "UPDATE pending_events SET image = $1 WHERE id = $2",
                                    full_url,
                                    uuid
                                ).execute(&pool).await;
                                
                                // Delete original file
                                let _ = fs::remove_file(&original_path).await;
                            }
                        }
                    });
                }
            },
            "thumbnail" => {
                let thumb_data = field.bytes().await.map_err(|e| {
                    ApiError::ValidationError(format!("Failed to read thumbnail: {}", e))
                })?;
                
                if !thumb_data.is_empty() {
                    let uuid = Uuid::new_v4();
                    let original_path = format!("uploads/events/thumb_original_{}.jpg", uuid);
                    
                    fs::create_dir_all("uploads/events").await.map_err(|e| {
                        ApiError::FileError(e)
                    })?;
                    
                    fs::write(&original_path, &thumb_data).await.map_err(|e| {
                        ApiError::FileError(e)
                    })?;
                    
                    thumbnail_path = Some(original_path.clone());
                    
                    // Convert thumbnail to WebP in background
                    let pool = state.pool.clone();
                    tokio::spawn(async move {
                        if let Ok(webp_data) = convert_to_webp(&thumb_data).await {
                            let webp_path = format!("uploads/events/thumb_{}.webp", uuid);
                            if fs::write(&webp_path, webp_data).await.is_ok() {
                                    let full_url = format!("https://api.rockvilletollandsda.church/{}", webp_path);
				    let _ = sqlx::query!(
                                    "UPDATE pending_events SET thumbnail = $1 WHERE id = $2",
                                    full_url,
                                    uuid
                                ).execute(&pool).await;
                                
                                let _ = fs::remove_file(&original_path).await;
                            }
                        }
                    });
                }
            },
            _ => {
                // Ignore unknown fields
                let _ = field.bytes().await;
            }
        }
    }

    // Validate required fields
    if req.title.is_empty() {
        return Err(ApiError::ValidationError("Title is required".to_string()));
    }
    if req.description.is_empty() {
        return Err(ApiError::ValidationError("Description is required".to_string()));
    }

    if req.location.is_empty() {
        return Err(ApiError::ValidationError("Location is required".to_string()));
    }
    if req.category.is_empty() {
        return Err(ApiError::ValidationError("Category is required".to_string()));
    }
    if req.bulletin_week.is_empty() {
        req.bulletin_week = "current".to_string(); // Default value
    }
    println!("DEBUG: About to insert - bulletin_week: '{}', is_empty: {}", req.bulletin_week, req.bulletin_week.is_empty());
    // Submit to database first
    let pending_event = db::events::submit_for_approval(&state.pool, req).await?;
    
    
    if let Some(thumb_path) = thumbnail_path {
        sqlx::query!(
            "UPDATE pending_events SET thumbnail = $1 WHERE id = $2", 
            thumb_path,
            pending_event.id
        ).execute(&state.pool).await.map_err(ApiError::DatabaseError)?;
    }
    
    // Send email notification to admin (existing logic)
    let mailer = state.mailer.clone();
    let event_for_email = pending_event.clone();
    tokio::spawn(async move {
        if let Err(e) = mailer.send_event_submission_notification(&event_for_email).await {
            tracing::error!("Failed to send email: {:?}", e);
        } else {
            tracing::info!("Email sent for event: {}", event_for_email.title);
        }
    });
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some(pending_event),
        message: Some("Event submitted successfully! Images are being optimized in the background.".to_string()),
    }))
}

// Simple stubs for other methods
pub async fn upcoming(State(state): State<AppState>) -> Result<Json<ApiResponse<Vec<Event>>>> {
    let events = db::events::get_upcoming(&state.pool, 10).await?;
    Ok(Json(ApiResponse { success: true, data: Some(events), message: None }))
}

pub async fn featured(State(state): State<AppState>) -> Result<Json<ApiResponse<Vec<Event>>>> {
    let events = db::events::get_featured(&state.pool).await?;
    Ok(Json(ApiResponse { success: true, data: Some(events), message: None }))
}

pub async fn get(State(state): State<AppState>, Path(id): Path<Uuid>) -> Result<Json<ApiResponse<Event>>> {
    let event = db::events::get_by_id(&state.pool, &id).await?;
    Ok(Json(ApiResponse { success: true, data: event, message: None }))
}

// Stubs for everything else
pub async fn create(
    State(state): State<AppState>,
    Json(req): Json<CreateEventRequest>,
) -> Result<Json<ApiResponse<Event>>> {
    let event = crate::db::events::create(&state.pool, req).await?;
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some(event),
        message: Some("Event created successfully".to_string()),
    }))
}

pub async fn update(
    Path(id): Path<Uuid>,
    State(state): State<AppState>,
    Json(req): Json<CreateEventRequest>,
) -> Result<Json<ApiResponse<Event>>> {
    let event = crate::db::events::update(&state.pool, &id, req).await?
        .ok_or_else(|| ApiError::NotFound("Event not found".to_string()))?;
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some(event),
        message: Some("Event updated successfully".to_string()),
    }))
}

pub async fn delete(
    Path(id): Path<Uuid>,
    State(state): State<AppState>,
) -> Result<Json<ApiResponse<String>>> {
    crate::db::events::delete(&state.pool, &id).await?;
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some("Event deleted successfully".to_string()),
        message: Some("Event deleted successfully".to_string()),
    }))
}

pub async fn list_pending(
    Query(params): Query<PaginationParams>,
    State(state): State<AppState>,
) -> Result<Json<ApiResponse<(Vec<PendingEvent>, i64)>>> {
    let (events, total) = crate::db::events::list_pending(&state.pool, params.page.unwrap_or(1) as i32, params.per_page.unwrap_or(10)).await?;
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some((events, total)),
        message: None,
    }))
}

pub async fn approve(
    Path(id): Path<Uuid>,
    State(state): State<AppState>,
    Json(req): Json<ApproveRejectRequest>,
) -> Result<Json<ApiResponse<Event>>> {
    let pending_event = crate::db::events::get_pending_by_id(&state.pool, &id).await?
        .ok_or_else(|| ApiError::NotFound("Pending event not found".to_string()))?;
    
    let event = crate::db::events::approve_pending(&state.pool, &id, req.admin_notes.clone()).await?;
    
    if let Some(_submitter_email) = &pending_event.submitter_email {
        let _ = state.mailer.send_event_approval_notification(&pending_event, req.admin_notes.as_deref()).await;
    }
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some(event),
        message: Some("Event approved successfully".to_string()),
    }))
}

pub async fn reject(
    Path(id): Path<Uuid>,
    State(state): State<AppState>,
    Json(req): Json<ApproveRejectRequest>,
) -> Result<Json<ApiResponse<String>>> {
    let pending_event = crate::db::events::get_pending_by_id(&state.pool, &id).await?
        .ok_or_else(|| ApiError::NotFound("Pending event not found".to_string()))?;
    
    crate::db::events::reject_pending(&state.pool, &id, req.admin_notes.clone()).await?;
    
    if let Some(_submitter_email) = &pending_event.submitter_email {
        let _ = state.mailer.send_event_rejection_notification(&pending_event, req.admin_notes.as_deref()).await;
    }
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some("Event rejected".to_string()),
        message: Some("Event rejected successfully".to_string()),
    }))
}

pub async fn current(State(_): State<AppState>) -> Result<Json<ApiResponse<String>>> {
    Ok(Json(ApiResponse { success: true, data: Some("Current - n/a".to_string()), message: None }))
}

pub async fn get_schedules(State(_): State<AppState>) -> Result<Json<ApiResponse<String>>> {
    Ok(Json(ApiResponse { success: true, data: Some("Schedules - n/a".to_string()), message: None }))
}

pub async fn update_schedules(State(_): State<AppState>) -> Result<Json<ApiResponse<String>>> {
    Ok(Json(ApiResponse { success: true, data: Some("Update schedules - n/a".to_string()), message: None }))
}

pub async fn get_app_version(State(_): State<AppState>) -> Result<Json<ApiResponse<String>>> {
    Ok(Json(ApiResponse { success: true, data: Some("App version - n/a".to_string()), message: None }))
}

pub async fn upload(State(_): State<AppState>) -> Result<Json<ApiResponse<String>>> {
    Ok(Json(ApiResponse { success: true, data: Some("Upload - n/a".to_string()), message: None }))
}

#[derive(Debug, Deserialize)]
pub struct ApproveRejectRequest {
    pub admin_notes: Option<String>,
}

pub async fn delete_pending(
    Path(id): Path<Uuid>,
    State(state): State<AppState>,
) -> Result<Json<ApiResponse<String>>> {
    // Delete the pending event directly from the database
    let result = sqlx::query!("DELETE FROM pending_events WHERE id = $1", id)
        .execute(&state.pool)
        .await
        .map_err(|_| ApiError::ValidationError("Failed to delete pending event".to_string()))?;
    
    if result.rows_affected() == 0 {
        return Err(ApiError::NotFound("Pending event not found".to_string()));
    }
    
    Ok(Json(ApiResponse {
        success: true,
        data: Some("Pending event deleted successfully".to_string()),
        message: Some("Pending event deleted successfully".to_string()),
    }))
}
