use chrono::{DateTime, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::utils::sanitize::{SanitizeOutput, sanitize_string, sanitize_option_string};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaItem {
    pub id: Uuid,
    pub title: String,
    pub speaker: Option<String>,
    pub date: Option<NaiveDate>,
    pub description: Option<String>,
    pub scripture_reading: Option<String>,
    
    // File information
    pub file_path: String,
    pub file_size: Option<i64>,
    pub duration_seconds: Option<i32>,
    
    // Media format info
    pub video_codec: Option<String>,
    pub audio_codec: Option<String>,
    pub resolution: Option<String>,
    pub bitrate: Option<i32>,
    
    // Thumbnail info
    pub thumbnail_path: Option<String>,
    pub thumbnail_generated_at: Option<DateTime<Utc>>,
    
    // Metadata
    pub nfo_path: Option<String>,
    pub last_scanned: Option<DateTime<Utc>>,
    pub created_at: Option<DateTime<Utc>>,
    pub updated_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TranscodedMedia {
    pub id: Uuid,
    pub media_item_id: Uuid,
    
    // Format info
    pub target_codec: String,
    pub target_resolution: Option<String>,
    pub target_bitrate: Option<i32>,
    
    // File info
    pub file_path: String,
    pub file_size: Option<i64>,
    
    // Transcoding status
    pub status: TranscodingStatus,
    pub transcoded_at: Option<DateTime<Utc>>,
    pub transcoding_started_at: Option<DateTime<Utc>>,
    pub error_message: Option<String>,
    
    // Performance metrics
    pub transcoding_duration_seconds: Option<i32>,
    pub transcoding_method: Option<String>,
    
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TranscodingStatus {
    Pending,
    Processing,
    Completed,
    Failed,
}

impl std::fmt::Display for TranscodingStatus {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            TranscodingStatus::Pending => write!(f, "pending"),
            TranscodingStatus::Processing => write!(f, "processing"),
            TranscodingStatus::Completed => write!(f, "completed"),
            TranscodingStatus::Failed => write!(f, "failed"),
        }
    }
}

impl std::str::FromStr for TranscodingStatus {
    type Err = String;
    
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "pending" => Ok(TranscodingStatus::Pending),
            "processing" => Ok(TranscodingStatus::Processing),
            "completed" => Ok(TranscodingStatus::Completed),
            "failed" => Ok(TranscodingStatus::Failed),
            _ => Err(format!("Invalid transcoding status: {}", s)),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaScanStatus {
    pub id: Uuid,
    pub scan_path: String,
    pub last_scan: DateTime<Utc>,
    pub files_found: i32,
    pub files_processed: i32,
    pub errors: Vec<String>,
    pub created_at: DateTime<Utc>,
}

// API response models
#[derive(Debug, Serialize, Deserialize)]
pub struct MediaItemResponse {
    pub id: String,
    pub title: String,
    pub speaker: Option<String>,
    pub date: Option<String>, // YYYY-MM-DD format
    pub description: Option<String>,
    pub scripture_reading: Option<String>,
    pub duration: Option<String>, // HH:MM:SS format
    pub audio_url: Option<String>,
    pub video_url: Option<String>,
    pub thumbnail: Option<String>,
    pub media_type: Option<String>,
}

impl MediaItem {
    pub fn to_response(&self, base_url: &str) -> MediaItemResponse {
        let duration = self.duration_seconds.map(|seconds| {
            let hours = seconds / 3600;
            let minutes = (seconds % 3600) / 60;
            let secs = seconds % 60;
            
            if hours > 0 {
                format!("{}:{:02}:{:02}", hours, minutes, secs)
            } else {
                format!("{}:{:02}", minutes, secs)
            }
        });

        let date = self.date.map(|d| d.format("%Y-%m-%d").to_string());
        
        // Determine media type and URLs
        let (audio_url, video_url, media_type) = if self.video_codec.is_some() {
            (None, Some(format!("{}/api/media/stream/{}", base_url, self.id)), Some("Video".to_string()))
        } else {
            (Some(format!("{}/api/media/stream/{}", base_url, self.id)), None, Some("Audio".to_string()))
        };

        let thumbnail = self.thumbnail_path.as_ref().map(|_| {
            format!("{}/api/media/thumbnail/{}", base_url, self.id)
        });

        MediaItemResponse {
            id: self.id.to_string(),
            title: self.title.clone(),
            speaker: self.speaker.clone(),
            date,
            description: self.description.clone(),
            scripture_reading: self.scripture_reading.clone(),
            duration,
            audio_url,
            video_url,
            thumbnail,
            media_type,
        }
    }
}

// Request models for creating/updating media items
#[derive(Debug, Deserialize)]
pub struct CreateMediaItemRequest {
    pub title: String,
    pub speaker: Option<String>,
    pub date: Option<NaiveDate>,
    pub description: Option<String>,
    pub file_path: String,
}

#[derive(Debug, Deserialize)]
pub struct TranscodingRequest {
    pub media_item_id: Uuid,
    pub target_codec: String,
    pub target_resolution: Option<String>,
    pub target_bitrate: Option<i32>,
}

// Query parameters
#[derive(Debug, Deserialize)]
pub struct MediaQuery {
    pub limit: Option<u32>,
    pub page: Option<u32>,
    pub speaker: Option<String>,
    pub date_from: Option<NaiveDate>,
    pub date_to: Option<NaiveDate>,
    pub search: Option<String>,
}

// SanitizeOutput implementations for media models
impl SanitizeOutput for MediaItem {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.speaker = sanitize_option_string(self.speaker);
        self.description = sanitize_option_string(self.description);
        self.scripture_reading = sanitize_option_string(self.scripture_reading);
        self.video_codec = sanitize_option_string(self.video_codec);
        self.audio_codec = sanitize_option_string(self.audio_codec);
        self.resolution = sanitize_option_string(self.resolution);
        self
    }
}

impl SanitizeOutput for MediaItemResponse {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.speaker = sanitize_option_string(self.speaker);
        self.description = sanitize_option_string(self.description);
        self.scripture_reading = sanitize_option_string(self.scripture_reading);
        self.media_type = sanitize_option_string(self.media_type);
        self
    }
}

impl SanitizeOutput for TranscodedMedia {
    fn sanitize_output(mut self) -> Self {
        self.target_codec = sanitize_string(self.target_codec);
        self.target_resolution = sanitize_option_string(self.target_resolution);
        self.error_message = sanitize_option_string(self.error_message);
        self.transcoding_method = sanitize_option_string(self.transcoding_method);
        self
    }
}