use sqlx::PgPool;
use uuid::Uuid;
use crate::{
    db,
    models::{Event, PendingEvent, CreateEventRequest, SubmitEventRequest},
    error::Result,
    utils::{
        urls::UrlBuilder,
        converters::{convert_events_to_v1, convert_event_to_v1, convert_pending_event_to_v1, convert_events_to_v2, convert_event_to_v2, convert_pending_events_to_v1},
    },
};

/// Event business logic service
/// Contains all event-related business logic, keeping handlers thin and focused on HTTP concerns
pub struct EventService;

impl EventService {
    /// Get upcoming events with V1 timezone conversion
    pub async fn get_upcoming_v1(pool: &PgPool, _limit: i64, url_builder: &UrlBuilder) -> Result<Vec<Event>> {
        let events = db::events::get_upcoming(pool).await?;
        convert_events_to_v1(events, url_builder)
    }

    /// Get featured events with V1 timezone conversion
    pub async fn get_featured_v1(pool: &PgPool, _limit: i64, url_builder: &UrlBuilder) -> Result<Vec<Event>> {
        let events = db::events::get_featured(pool).await?;
        convert_events_to_v1(events, url_builder)
    }

    /// Get all events with V1 timezone conversion and pagination
    pub async fn list_v1(pool: &PgPool, url_builder: &UrlBuilder) -> Result<Vec<Event>> {
        let events = db::events::list(pool).await?;
        convert_events_to_v1(events, url_builder)
    }

    /// Get single event by ID with V1 timezone conversion
    pub async fn get_by_id_v1(pool: &PgPool, id: &Uuid, url_builder: &UrlBuilder) -> Result<Option<Event>> {
        if let Some(event) = db::events::get_by_id(pool, id).await? {
            let converted = convert_event_to_v1(event, url_builder)?;
            Ok(Some(converted))
        } else {
            Ok(None)
        }
    }

    /// Create a new event (admin function)
    pub async fn create(pool: &PgPool, request: CreateEventRequest, url_builder: &UrlBuilder) -> Result<Event> {
        let event_id = uuid::Uuid::new_v4();
        let event = db::events::create(pool, &event_id, &request).await?;
        convert_event_to_v1(event, url_builder)
    }

    /// Submit event for approval (public function)
    pub async fn submit_for_approval(pool: &PgPool, request: SubmitEventRequest, url_builder: &UrlBuilder) -> Result<PendingEvent> {
        let pending_event = db::events::submit_for_approval(pool, request).await?;
        convert_pending_event_to_v1(pending_event, url_builder)
    }

    /// Get pending events list (admin function)
    pub async fn list_pending_v1(pool: &PgPool, page: i32, per_page: i32, url_builder: &UrlBuilder) -> Result<Vec<PendingEvent>> {
        let events = db::events::list_pending(pool, page, per_page).await?;
        convert_pending_events_to_v1(events, url_builder)
    }

    /// Count pending events (admin function)
    pub async fn count_pending(pool: &PgPool) -> Result<i64> {
        db::events::count_pending(pool).await
    }

    // V2 Service Methods with flexible timezone handling
    
    /// Get upcoming events with V2 timezone handling
    pub async fn get_upcoming_v2(pool: &PgPool, _limit: i64, timezone: &str, url_builder: &UrlBuilder) -> Result<Vec<crate::models::EventV2>> {
        let events = db::events::get_upcoming(pool).await?;
        convert_events_to_v2(events, timezone, url_builder)
    }

    /// Get featured events with V2 timezone handling
    pub async fn get_featured_v2(pool: &PgPool, _limit: i64, timezone: &str, url_builder: &UrlBuilder) -> Result<Vec<crate::models::EventV2>> {
        let events = db::events::get_featured(pool).await?;
        convert_events_to_v2(events, timezone, url_builder)
    }

    /// Get all events with V2 timezone handling and pagination
    pub async fn list_v2(pool: &PgPool, timezone: &str, url_builder: &UrlBuilder) -> Result<Vec<crate::models::EventV2>> {
        let events = db::events::list(pool).await?;
        convert_events_to_v2(events, timezone, url_builder)
    }

    /// Get single event by ID with V2 timezone handling
    pub async fn get_by_id_v2(pool: &PgPool, id: &Uuid, timezone: &str, url_builder: &UrlBuilder) -> Result<Option<crate::models::EventV2>> {
        if let Some(event) = db::events::get_by_id(pool, id).await? {
            let converted = convert_event_to_v2(event, timezone, url_builder)?;
            Ok(Some(converted))
        } else {
            Ok(None)
        }
    }

    /// Business logic for approving pending events
    pub async fn approve_pending_event(pool: &PgPool, id: &Uuid) -> Result<Event> {
        // Future: Add business logic like validation, notifications, etc.
        db::events::approve_pending(pool, id, None).await
    }

    /// Business logic for rejecting pending events
    pub async fn reject_pending_event(pool: &PgPool, id: &Uuid, reason: Option<String>) -> Result<()> {
        // Future: Add business logic like validation, notifications, etc.
        db::events::reject_pending(pool, id, reason).await
    }

    /// Business logic for updating events
    pub async fn update_event(pool: &PgPool, id: &Uuid, request: CreateEventRequest) -> Result<Event> {
        // Future: Add business logic like validation, authorization checks, etc.
        db::events::update(pool, id, request).await?
            .ok_or_else(|| crate::error::ApiError::NotFound("Event not found".to_string()))
    }

    /// Business logic for deleting events
    pub async fn delete_event(pool: &PgPool, id: &Uuid) -> Result<()> {
        // Future: Add business logic like cascade checks, authorization, etc.
        db::events::delete(pool, id).await
    }

    /// Business logic for deleting pending events
    pub async fn delete_pending_event(pool: &PgPool, id: &Uuid) -> Result<()> {
        // Future: Add business logic like authorization checks, cleanup, etc.
        db::events::delete_pending(pool, id).await
    }
}