//! Download events for progress tracking and status updates

use serde::{Deserialize, Serialize};

/// Events emitted during download operations
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum DownloadEvent {
    /// Download has been queued
    #[serde(rename_all = "camelCase")]
    Queued { download_id: i64, item_id: String },
    /// Download has started
    #[serde(rename_all = "camelCase")]
    Started { download_id: i64, item_id: String },
    /// Download progress update
    #[serde(rename_all = "camelCase")]
    Progress {
        download_id: i64,
        item_id: String,
        bytes_downloaded: i64,
        total_bytes: Option<i64>,
        progress: f64, // 0.0 to 1.0
    },
    /// Download completed successfully
    #[serde(rename_all = "camelCase")]
    Completed {
        download_id: i64,
        item_id: String,
        file_path: String,
    },
    /// Download failed with error
    #[serde(rename_all = "camelCase")]
    Failed {
        download_id: i64,
        item_id: String,
        error: String,
    },
    /// Download paused
    #[serde(rename_all = "camelCase")]
    Paused { download_id: i64, item_id: String },
    /// Download cancelled
    #[serde(rename_all = "camelCase")]
    Cancelled { download_id: i64, item_id: String },
    /// The queue is holding: WiFi-only is enabled and the current network is
    /// metered/cellular. Pending rows stay pending and resume on network change.
    ///
    /// TRACES: UR-053 | DR-074
    WaitingForNetwork,
}

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

    #[test]
    fn test_download_event_serialization_roundtrip() {
        let event = DownloadEvent::Progress {
            download_id: 1,
            item_id: "test123".to_string(),
            bytes_downloaded: 1024,
            total_bytes: Some(2048),
            progress: 0.5,
        };

        let json = serde_json::to_string(&event).unwrap();
        let deserialized: DownloadEvent = serde_json::from_str(&json).unwrap();

        match deserialized {
            DownloadEvent::Progress {
                download_id,
                item_id,
                progress,
                ..
            } => {
                assert_eq!(download_id, 1);
                assert_eq!(item_id, "test123");
                assert_eq!(progress, 0.5);
            }
            _ => panic!("Wrong variant"),
        }
    }

    #[test]
    fn test_download_event_completed() {
        let event = DownloadEvent::Completed {
            download_id: 42,
            item_id: "song456".to_string(),
            file_path: "/path/to/file.mp3".to_string(),
        };

        let json = serde_json::to_string(&event).unwrap();
        assert!(json.contains("\"type\":\"completed\""));
        // Verify camelCase field names
        assert!(
            json.contains("\"downloadId\":42"),
            "Expected downloadId (camelCase), got: {}",
            json
        );
        assert!(
            json.contains("\"itemId\":\"song456\""),
            "Expected itemId (camelCase), got: {}",
            json
        );
        assert!(
            json.contains("\"filePath\":"),
            "Expected filePath (camelCase), got: {}",
            json
        );

        // Verify roundtrip
        let deserialized: DownloadEvent = serde_json::from_str(&json).unwrap();
        match deserialized {
            DownloadEvent::Completed { file_path, .. } => {
                assert_eq!(file_path, "/path/to/file.mp3");
            }
            _ => panic!("Wrong variant"),
        }
    }

    #[test]
    fn test_download_event_failed() {
        let event = DownloadEvent::Failed {
            download_id: 10,
            item_id: "failed_item".to_string(),
            error: "Network timeout".to_string(),
        };

        let json = serde_json::to_string(&event).unwrap();
        assert!(json.contains("\"type\":\"failed\""));

        // Verify roundtrip
        let deserialized: DownloadEvent = serde_json::from_str(&json).unwrap();
        match deserialized {
            DownloadEvent::Failed { error, .. } => {
                assert_eq!(error, "Network timeout");
            }
            _ => panic!("Wrong variant"),
        }
    }
}
