//! Track type definition
//! 
//! This module defines the Track type and related structures.

use serde::{Deserialize, Serialize};
use crate::types::TrackId;
use chrono::{DateTime, Utc};

/// Track information
/// 
/// Represents an audio track in the Veza system.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Track {
    /// Track ID
    pub id: TrackId,
    /// Track title
    pub title: String,
    /// Track artist
    pub artist: String,
    /// Optional album name
    #[serde(skip_serializing_if = "Option::is_none")]
    pub album: Option<String>,
    /// Track duration in seconds
    pub duration: u64,
    /// Optional file URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub file_url: Option<String>,
    /// Optional cover image URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cover_url: Option<String>,
    /// Track creation timestamp
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_at: Option<DateTime<Utc>>,
    /// Track last update timestamp
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<DateTime<Utc>>,
}

impl Track {
    /// Create a new Track instance
    pub fn new(id: TrackId, title: String, artist: String, duration: u64) -> Self {
        Self {
            id,
            title,
            artist,
            album: None,
            duration,
            file_url: None,
            cover_url: None,
            created_at: None,
            updated_at: None,
        }
    }

    /// Validate track data
    pub fn validate(&self) -> Result<(), String> {
        if self.title.is_empty() {
            return Err("Title cannot be empty".to_string());
        }
        if self.artist.is_empty() {
            return Err("Artist cannot be empty".to_string());
        }
        if self.duration == 0 {
            return Err("Duration must be greater than 0".to_string());
        }
        Ok(())
    }

    /// Format duration as MM:SS or HH:MM:SS
    pub fn formatted_duration(&self) -> String {
        let hours = self.duration / 3600;
        let minutes = (self.duration % 3600) / 60;
        let seconds = self.duration % 60;

        if hours > 0 {
            format!("{}:{:02}:{:02}", hours, minutes, seconds)
        } else {
            format!("{}:{:02}", minutes, seconds)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use uuid::Uuid;

    #[test]
    fn test_track_new() {
        let track_id = Uuid::new_v4();
        let track = Track::new(track_id, "Test Song".to_string(), "Test Artist".to_string(), 180);
        assert_eq!(track.id, track_id);
        assert_eq!(track.title, "Test Song");
        assert_eq!(track.artist, "Test Artist");
        assert_eq!(track.duration, 180);
        assert!(track.album.is_none());
        assert!(track.file_url.is_none());
        assert!(track.cover_url.is_none());
    }

    #[test]
    fn test_track_serialize() {
        let track_id = Uuid::new_v4();
        let track = Track::new(track_id, "Test Song".to_string(), "Test Artist".to_string(), 180);
        let json = serde_json::to_string(&track).unwrap();
        assert!(json.contains("\"title\":\"Test Song\""));
        assert!(json.contains("\"artist\":\"Test Artist\""));
        assert!(json.contains("\"duration\":180"));
    }

    #[test]
    fn test_track_deserialize() {
        let track_id = Uuid::new_v4();
        let json = format!(
            r#"{{"id":"{}","title":"Test Song","artist":"Test Artist","duration":180}}"#,
            track_id
        );
        let track: Track = serde_json::from_str(&json).unwrap();
        assert_eq!(track.id, track_id);
        assert_eq!(track.title, "Test Song");
        assert_eq!(track.artist, "Test Artist");
        assert_eq!(track.duration, 180);
    }

    #[test]
    fn test_track_validate_success() {
        let track_id = Uuid::new_v4();
        let track = Track::new(track_id, "Test Song".to_string(), "Test Artist".to_string(), 180);
        assert!(track.validate().is_ok());
    }

    #[test]
    fn test_track_validate_empty_title() {
        let track_id = Uuid::new_v4();
        let track = Track::new(track_id, "".to_string(), "Test Artist".to_string(), 180);
        assert!(track.validate().is_err());
    }

    #[test]
    fn test_track_validate_empty_artist() {
        let track_id = Uuid::new_v4();
        let track = Track::new(track_id, "Test Song".to_string(), "".to_string(), 180);
        assert!(track.validate().is_err());
    }

    #[test]
    fn test_track_validate_zero_duration() {
        let track_id = Uuid::new_v4();
        let track = Track::new(track_id, "Test Song".to_string(), "Test Artist".to_string(), 0);
        assert!(track.validate().is_err());
    }

    #[test]
    fn test_track_formatted_duration() {
        let track_id = Uuid::new_v4();
        let track = Track::new(track_id, "Test Song".to_string(), "Test Artist".to_string(), 125);
        assert_eq!(track.formatted_duration(), "2:05");
        
        let track_long = Track::new(track_id, "Test Song".to_string(), "Test Artist".to_string(), 3665);
        assert_eq!(track_long.formatted_duration(), "1:01:05");
    }
}

