use sqlx::PgPool;
use uuid::Uuid;
use crate::{
    db,
    models::{Bulletin, BulletinV2, CreateBulletinRequest},
    error::Result,
    utils::{
        urls::UrlBuilder,
        converters::{convert_bulletins_to_v1, convert_bulletin_to_v1, convert_bulletins_to_v2, convert_bulletin_to_v2},
        db_operations::BulletinOperations,
    },
    handlers::bulletins_shared::{process_bulletins_batch, process_single_bulletin},
};

/// Bulletin business logic service
/// Contains all bulletin-related business logic, keeping handlers thin and focused on HTTP concerns
pub struct BulletinService;

impl BulletinService {
    /// Get paginated list of bulletins with V1 timezone conversion (EST)
    pub async fn list_v1(
        pool: &PgPool, 
        page: i32, 
        per_page: i64, 
        active_only: bool,
        url_builder: &UrlBuilder
    ) -> Result<(Vec<Bulletin>, i64)> {
        let (mut bulletins, total) = db::bulletins::list(pool, page, per_page, active_only).await?;
        
        // Apply shared processing logic
        process_bulletins_batch(pool, &mut bulletins).await?;
        
        // Convert UTC times to EST for V1 compatibility
        let converted_bulletins = convert_bulletins_to_v1(bulletins, url_builder)?;
        
        Ok((converted_bulletins, total))
    }

    /// Get current bulletin with V1 timezone conversion (EST)
    pub async fn get_current_v1(pool: &PgPool, url_builder: &UrlBuilder) -> Result<Option<Bulletin>> {
        let mut bulletin = BulletinOperations::get_current(pool).await?;
        
        if let Some(ref mut bulletin_data) = bulletin {
            process_single_bulletin(pool, bulletin_data).await?;
        }
        
        // Convert UTC times to EST for V1 compatibility
        match bulletin {
            Some(b) => {
                let converted = convert_bulletin_to_v1(b, url_builder)?;
                Ok(Some(converted))
            },
            None => Ok(None),
        }
    }

    /// Get next bulletin with V1 timezone conversion (EST)
    pub async fn get_next_v1(pool: &PgPool, url_builder: &UrlBuilder) -> Result<Option<Bulletin>> {
        let mut bulletin = BulletinOperations::get_next(pool).await?;
        
        if let Some(ref mut bulletin_data) = bulletin {
            process_single_bulletin(pool, bulletin_data).await?;
        }
        
        // Convert UTC times to EST for V1 compatibility
        match bulletin {
            Some(b) => {
                let converted = convert_bulletin_to_v1(b, url_builder)?;
                Ok(Some(converted))
            },
            None => Ok(None),
        }
    }

    /// Get bulletin by ID with V1 timezone conversion (EST)
    pub async fn get_by_id_v1(pool: &PgPool, id: &Uuid, url_builder: &UrlBuilder) -> Result<Option<Bulletin>> {
        let mut bulletin = crate::utils::db_operations::DbOperations::get_bulletin_by_id(pool, id).await?;
        
        match bulletin {
            Some(ref mut bulletin_data) => {
                process_single_bulletin(pool, bulletin_data).await?;
                let converted = convert_bulletin_to_v1(bulletin_data.clone(), url_builder)?;
                Ok(Some(converted))
            },
            None => Ok(None),
        }
    }

    /// Create a new bulletin
    pub async fn create(pool: &PgPool, request: CreateBulletinRequest, url_builder: &UrlBuilder) -> Result<Bulletin> {
        let bulletin = db::bulletins::create(pool, request).await?;
        
        // Convert UTC times to EST for V1 compatibility
        convert_bulletin_to_v1(bulletin, url_builder)
    }

    /// Update a bulletin
    pub async fn update(pool: &PgPool, id: &Uuid, request: CreateBulletinRequest, url_builder: &UrlBuilder) -> Result<Option<Bulletin>> {
        let bulletin = db::bulletins::update(pool, id, request).await?;
        
        match bulletin {
            Some(b) => {
                let converted = convert_bulletin_to_v1(b, url_builder)?;
                Ok(Some(converted))
            },
            None => Ok(None),
        }
    }

    /// Delete a bulletin
    pub async fn delete(pool: &PgPool, id: &Uuid) -> Result<()> {
        db::bulletins::delete(pool, id).await
    }

    // V2 API methods (UTC timezone as per shared converter)

    /// Get paginated list of bulletins with V2 format (UTC timestamps)
    pub async fn list_v2(
        pool: &PgPool, 
        page: i32, 
        per_page: i64, 
        active_only: bool,
        url_builder: &UrlBuilder
    ) -> Result<(Vec<BulletinV2>, i64)> {
        let (bulletins, total) = db::bulletins::list(pool, page, per_page, active_only).await?;
        
        // Convert to V2 format with UTC timestamps
        let converted_bulletins = convert_bulletins_to_v2(bulletins, url_builder)?;
        
        Ok((converted_bulletins, total))
    }

    /// Get current bulletin with V2 format (UTC timestamps)
    pub async fn get_current_v2(pool: &PgPool, url_builder: &UrlBuilder) -> Result<Option<BulletinV2>> {
        let bulletin = db::bulletins::get_current(pool).await?;
        
        match bulletin {
            Some(b) => {
                let converted = convert_bulletin_to_v2(b, url_builder)?;
                Ok(Some(converted))
            },
            None => Ok(None),
        }
    }

    /// Get next bulletin with V2 format (UTC timestamps)
    pub async fn get_next_v2(pool: &PgPool, url_builder: &UrlBuilder) -> Result<Option<BulletinV2>> {
        let bulletin = BulletinOperations::get_next(pool).await?;
        
        match bulletin {
            Some(b) => {
                let converted = convert_bulletin_to_v2(b, url_builder)?;
                Ok(Some(converted))
            },
            None => Ok(None),
        }
    }

    /// Get bulletin by ID with V2 format (UTC timestamps)
    pub async fn get_by_id_v2(pool: &PgPool, id: &Uuid, url_builder: &UrlBuilder) -> Result<Option<BulletinV2>> {
        let bulletin = db::bulletins::get_by_id(pool, id).await?;
        
        match bulletin {
            Some(b) => {
                let converted = convert_bulletin_to_v2(b, url_builder)?;
                Ok(Some(converted))
            },
            None => Ok(None),
        }
    }
}