//! Thumbnail download worker

use std::time::Duration;

/// Worker for downloading thumbnails from Jellyfin server
pub struct ThumbnailWorker {
    client: reqwest::Client,
}

impl ThumbnailWorker {
    /// Create a new thumbnail worker
    pub fn new() -> Self {
        let client = reqwest::Client::builder()
            .timeout(Duration::from_secs(30))
            .https_only(true)
            .build()
            .expect("Failed to create HTTP client");

        Self { client }
    }

    /// Download a thumbnail from URL
    pub async fn download(&self, url: &str) -> Result<Vec<u8>, ThumbnailDownloadError> {
        let response = self
            .client
            .get(url)
            .send()
            .await
            .map_err(|e| ThumbnailDownloadError::Network(e.to_string()))?;

        let status = response.status();
        if !status.is_success() {
            return Err(ThumbnailDownloadError::Http(status.as_u16()));
        }

        let bytes = response
            .bytes()
            .await
            .map_err(|e| ThumbnailDownloadError::Network(e.to_string()))?;

        Ok(bytes.to_vec())
    }

    /// Download with retry logic
    pub async fn download_with_retry(
        &self,
        url: &str,
        max_retries: u32,
    ) -> Result<Vec<u8>, ThumbnailDownloadError> {
        let mut last_error = ThumbnailDownloadError::Network("No attempts made".to_string());

        for attempt in 0..=max_retries {
            match self.download(url).await {
                Ok(data) => return Ok(data),
                Err(e) if e.is_retryable() && attempt < max_retries => {
                    last_error = e;
                    // Simple exponential backoff: 100ms, 200ms, 400ms
                    let delay = Duration::from_millis(100 * (1 << attempt));
                    tokio::time::sleep(delay).await;
                }
                Err(e) => return Err(e),
            }
        }

        Err(last_error)
    }
}

impl Default for ThumbnailWorker {
    fn default() -> Self {
        Self::new()
    }
}

/// Errors that can occur during thumbnail download
#[derive(Debug)]
pub enum ThumbnailDownloadError {
    Network(String),
    Http(u16),
}

impl ThumbnailDownloadError {
    /// Check if this error is retryable
    pub fn is_retryable(&self) -> bool {
        match self {
            ThumbnailDownloadError::Network(_) => true,
            ThumbnailDownloadError::Http(status) => *status >= 500,
        }
    }
}

impl std::fmt::Display for ThumbnailDownloadError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ThumbnailDownloadError::Network(msg) => write!(f, "Network error: {}", msg),
            ThumbnailDownloadError::Http(status) => write!(f, "HTTP error: {}", status),
        }
    }
}

impl std::error::Error for ThumbnailDownloadError {}

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

    #[test]
    fn test_error_retryable() {
        assert!(ThumbnailDownloadError::Network("timeout".to_string()).is_retryable());
        assert!(ThumbnailDownloadError::Http(500).is_retryable());
        assert!(ThumbnailDownloadError::Http(503).is_retryable());
        assert!(!ThumbnailDownloadError::Http(404).is_retryable());
        assert!(!ThumbnailDownloadError::Http(400).is_retryable());
    }

    #[test]
    fn test_worker_creation() {
        let _worker = ThumbnailWorker::new();
        // Just verify it doesn't panic
        let _default = ThumbnailWorker::default();
    }
}
