use sqlx::PgPool;
use uuid::Uuid;

use crate::{
    error::{ApiError, Result},
    models::{Event, PendingEvent, CreateEventRequest, SubmitEventRequest},
    utils::{
        sanitize::strip_html_tags,
        query::QueryBuilder,
        db_operations::{DbOperations, EventOperations},
    },
};

pub async fn list(pool: &PgPool) -> Result<Vec<Event>> {
    // Use shared query builder
    QueryBuilder::fetch_all(
        pool,
        "SELECT * FROM events ORDER BY start_time DESC LIMIT 50"
    ).await
}

pub async fn get_upcoming(pool: &PgPool) -> Result<Vec<Event>> {
    // Use shared operation
    EventOperations::get_upcoming(pool, 50).await
}

pub async fn get_featured(pool: &PgPool) -> Result<Vec<Event>> {
    // Use shared operation
    EventOperations::get_featured(pool, 10).await
}

pub async fn get_by_id(pool: &PgPool, id: &Uuid) -> Result<Option<Event>> {
    let event = sqlx::query_as!(Event, "SELECT * FROM events WHERE id = $1", id)
        .fetch_optional(pool)
        .await?;

    Ok(event)
}

pub async fn create(pool: &PgPool, _id: &Uuid, req: &CreateEventRequest) -> Result<Event> {
    // Use shared operation for create
    EventOperations::create(pool, req.clone()).await
}

pub async fn update(pool: &PgPool, id: &Uuid, req: CreateEventRequest) -> Result<Option<Event>> {
    // Use shared operation for update
    EventOperations::update(pool, id, req).await.map(Some)
}

pub async fn delete(pool: &PgPool, id: &Uuid) -> Result<()> {
    // Use shared operation for delete
    DbOperations::delete_by_id(pool, "events", id).await
}

// Pending events functions
pub async fn submit_for_approval(pool: &PgPool, req: SubmitEventRequest) -> Result<PendingEvent> {
    // Use shared operation for submit
    EventOperations::submit_pending(pool, req).await
}

// Legacy function for compatibility - remove after handlers are updated
pub async fn _submit_for_approval_legacy(pool: &PgPool, req: SubmitEventRequest) -> Result<PendingEvent> {
    let pending_event = sqlx::query_as!(
        PendingEvent,
        "INSERT INTO pending_events (title, description, start_time, end_time, location, location_url, image, thumbnail, 
                                   category, is_featured, recurring_type, bulletin_week, submitter_email) 
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) 
         RETURNING *",
        strip_html_tags(&req.title),
        strip_html_tags(&req.description),
        req.start_time,
        req.end_time,
        strip_html_tags(&req.location),
        req.location_url.as_ref().map(|s| strip_html_tags(s)),
	req.image,
	req.thumbnail,
        strip_html_tags(&req.category),
        req.is_featured.unwrap_or(false),
        req.recurring_type.as_ref().map(|s| strip_html_tags(s)),
        strip_html_tags(&req.bulletin_week),
        req.submitter_email.as_ref().map(|s| strip_html_tags(s)),
    )
    .fetch_one(pool)
    .await?;

    Ok(pending_event)
}

pub async fn list_pending(pool: &PgPool, page: i32, per_page: i32) -> Result<Vec<PendingEvent>> {
    let offset = ((page - 1) as i64) * (per_page as i64);

    let events = sqlx::query_as!(
        PendingEvent,
        "SELECT * FROM pending_events WHERE approval_status = 'pending' ORDER BY submitted_at DESC LIMIT $1 OFFSET $2",
        per_page as i64,
        offset
    )
    .fetch_all(pool)
    .await?;

    Ok(events)
}

pub async fn get_pending_by_id(pool: &PgPool, id: &Uuid) -> Result<Option<PendingEvent>> {
    let event = sqlx::query_as!(PendingEvent, "SELECT * FROM pending_events WHERE id = $1", id)
        .fetch_optional(pool)
        .await?;

    Ok(event)
}

pub async fn approve_pending(pool: &PgPool, id: &Uuid, admin_notes: Option<String>) -> Result<Event> {
    // Start transaction to move from pending to approved
    let mut tx = pool.begin().await?;

    // Get the pending event
    let pending = sqlx::query_as!(
        PendingEvent,
        "SELECT * FROM pending_events WHERE id = $1",
        id
    )
    .fetch_one(&mut *tx)
    .await?;

    // Create the approved event
    let event = sqlx::query_as!(
        Event,
        "INSERT INTO events (title, description, start_time, end_time, location, location_url, image, thumbnail,  category, is_featured, recurring_type, approved_from) 
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) 
         RETURNING *",
        pending.title,
        pending.description,
        pending.start_time,
        pending.end_time,
        pending.location,
        pending.location_url,
	pending.image,
	pending.thumbnail,
        pending.category,
        pending.is_featured,
        pending.recurring_type,
        pending.submitter_email
    )
    .fetch_one(&mut *tx)
    .await?;

    // Update pending event status
    sqlx::query!(
        "UPDATE pending_events SET approval_status = 'approved', admin_notes = $1, updated_at = NOW() WHERE id = $2",
        admin_notes,
        id
    )
    .execute(&mut *tx)
    .await?;

    tx.commit().await?;

    Ok(event)
}

pub async fn reject_pending(pool: &PgPool, id: &Uuid, admin_notes: Option<String>) -> Result<()> {
    let result = sqlx::query!(
        "UPDATE pending_events SET approval_status = 'rejected', admin_notes = $1, updated_at = NOW() WHERE id = $2",
        admin_notes,
        id
    )
    .execute(pool)
    .await?;

    if result.rows_affected() == 0 {
        return Err(ApiError::NotFound("Pending event not found".to_string()));
    }

    Ok(())
}

pub async fn submit(pool: &PgPool, id: &Uuid, req: &SubmitEventRequest) -> Result<PendingEvent> {
    let pending_event = sqlx::query_as!(
        PendingEvent,
        "INSERT INTO pending_events (id, title, description, start_time, end_time, location, location_url, image, thumbnail, 
                                   category, is_featured, recurring_type, bulletin_week, submitter_email) 
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) 
         RETURNING *",
        id,
        req.title,
        req.description,
        req.start_time,
        req.end_time,
        req.location,
        req.location_url,
        req.image,
        req.thumbnail,
        req.category,
        req.is_featured.unwrap_or(false),
        req.recurring_type,
        req.bulletin_week,
        req.submitter_email,
    )
    .fetch_one(pool)
    .await?;

    Ok(pending_event)
}

pub async fn update_pending_image(pool: &PgPool, id: &Uuid, image_path: &str) -> Result<()> {
    let result = sqlx::query!(
        "UPDATE pending_events SET image = $1, updated_at = NOW() WHERE id = $2",
        image_path,
        id
    )
    .execute(pool)
    .await?;

    if result.rows_affected() == 0 {
        return Err(ApiError::NotFound("Pending event not found".to_string()));
    }

    Ok(())
}

pub async fn count_pending(pool: &PgPool) -> Result<i64> {
    let count = sqlx::query_scalar!(
        "SELECT COUNT(*) FROM pending_events WHERE approval_status = 'pending'"
    )
    .fetch_one(pool)
    .await?
    .unwrap_or(0);

    Ok(count)
}

pub async fn delete_pending(pool: &PgPool, id: &Uuid) -> Result<()> {
    let result = sqlx::query!("DELETE FROM pending_events WHERE id = $1", id)
        .execute(pool)
        .await
        .map_err(|e| ApiError::Database(e.to_string()))?;
    
    if result.rows_affected() == 0 {
        return Err(ApiError::NotFound("Pending event not found".to_string()));
    }
    
    Ok(())
}


