use crate::models::PaginatedResponse;
use chrono::Utc;
use sqlx::PgPool;
use uuid::Uuid;

use crate::{
    error::{ApiError, Result},
    models::{Event, PendingEvent, CreateEventRequest, SubmitEventRequest},
};

pub async fn list(pool: &PgPool) -> Result<Vec<Event>> {
    let events = sqlx::query_as!(
        Event,
        "SELECT * FROM events ORDER BY start_time DESC LIMIT 50"
    )
    .fetch_all(pool)
    .await?;

    Ok(events)
}

pub async fn get_upcoming(pool: &PgPool, limit: i64) -> Result<Vec<Event>> {
    let events = sqlx::query_as!(
        Event,
        "SELECT * FROM events 
         WHERE start_time > NOW() 
         ORDER BY start_time ASC 
         LIMIT $1",
        limit
    )
    .fetch_all(pool)
    .await?;

    Ok(events)
}

pub async fn get_featured(pool: &PgPool) -> Result<Vec<Event>> {
    let events = sqlx::query_as!(
        Event,
        "SELECT * FROM events 
         WHERE is_featured = true AND start_time > NOW() 
         ORDER BY start_time ASC 
         LIMIT 10"
    )
    .fetch_all(pool)
    .await?;

    Ok(events)
}

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, req: CreateEventRequest) -> Result<Event> {
    let event = sqlx::query_as!(
        Event,
        "INSERT INTO events (title, description, start_time, end_time, location, location_url, category, is_featured, recurring_type) 
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) 
         RETURNING *",
        req.title,
        req.description,
        req.start_time,
        req.end_time,
        req.location,
        req.location_url,
        req.category,
        req.is_featured.unwrap_or(false),
        req.recurring_type
    )
    .fetch_one(pool)
    .await?;

    Ok(event)
}

pub async fn update(pool: &PgPool, id: &Uuid, req: CreateEventRequest) -> Result<Option<Event>> {
    let event = sqlx::query_as!(
        Event,
        "UPDATE events 
         SET title = $1, description = $2, start_time = $3, end_time = $4, location = $5, 
             location_url = $6, category = $7, is_featured = $8, recurring_type = $9, updated_at = NOW()
         WHERE id = $10 
         RETURNING *",
        req.title,
        req.description,
        req.start_time,
        req.end_time,
        req.location,
        req.location_url,
        req.category,
        req.is_featured.unwrap_or(false),
        req.recurring_type,
        id
    )
    .fetch_optional(pool)
    .await?;

    Ok(event)
}

pub async fn delete(pool: &PgPool, id: &Uuid) -> Result<()> {
    let result = sqlx::query!("DELETE FROM events WHERE id = $1", id)
        .execute(pool)
        .await?;

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

    Ok(())
}

// Pending events functions
pub async fn submit_for_approval(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, 
                                   category, is_featured, recurring_type, bulletin_week, submitter_email) 
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) 
         RETURNING *",
        req.title,
        req.description,
        req.start_time,
        req.end_time,
        req.location,
        req.location_url,
        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 list_pending(pool: &PgPool, page: i32, per_page: i64) -> Result<(Vec<PendingEvent>, i64)> {
    let offset = ((page - 1) as i64) * per_page;

    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,
        offset
    )
    .fetch_all(pool)
    .await?;

    let total = sqlx::query_scalar!("SELECT COUNT(*) FROM pending_events WHERE approval_status = 'pending'")
        .fetch_one(pool)
        .await?
        .unwrap_or(0);

    Ok((events, total))
}

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, category, is_featured, recurring_type, approved_from) 
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) 
         RETURNING *",
        pending.title,
        pending.description,
        pending.start_time,
        pending.end_time,
        pending.location,
        pending.location_url,
        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(())
}

