use serde::{Deserialize, Serialize};
use anyhow::{Result, anyhow};
use std::path::Path;
use std::time::Duration;
use reqwest::Client;
use tokio::fs;

/// 云端文件上传服务
/// 遵循 Tauri 开发规范的业务逻辑设计原则
pub struct CloudUploadService {
    client: Client,
    base_url: String,
    bearer_token: String,
    timeout: Duration,
}

/// 上传预签名请求
#[derive(Debug, Serialize)]
pub struct UploadPresignRequest {
    pub key: String,
    pub content_type: String,
}

/// 上传预签名响应
#[derive(Debug, Deserialize)]
pub struct UploadPresignResponse {
    pub url: String,
    pub urn: String,
    pub expired_at: String,
}

/// 上传结果
#[derive(Debug, Clone)]
pub struct UploadResult {
    pub success: bool,
    pub remote_url: Option<String>,
    pub urn: Option<String>,
    pub error_message: Option<String>,
    pub file_size: u64,
}

/// 上传进度回调
pub type ProgressCallback = Box<dyn Fn(u64, u64) + Send + Sync>;

impl CloudUploadService {
    /// 创建新的云端上传服务实例
    pub fn new() -> Self {
        let client = Client::builder()
            .timeout(Duration::from_secs(120))
            .build()
            .expect("Failed to create HTTP client");

        Self {
            client,
            base_url: "https://bowongai-dev--bowong-ai-video-gemini-fastapi-webapp.modal.run".to_string(),
            bearer_token: "bowong7777".to_string(),
            timeout: Duration::from_secs(120),
        }
    }

    /// 使用自定义配置创建服务实例
    pub fn with_config(base_url: String, bearer_token: String, timeout_secs: u64) -> Self {
        let client = Client::builder()
            .timeout(Duration::from_secs(timeout_secs))
            .build()
            .expect("Failed to create HTTP client");

        Self {
            client,
            base_url,
            bearer_token,
            timeout: Duration::from_secs(timeout_secs),
        }
    }

    /// 上传单个文件
    pub async fn upload_file(
        &self,
        file_path: &str,
        remote_key: Option<String>,
        progress_callback: Option<ProgressCallback>,
    ) -> Result<UploadResult> {
        // 检查文件是否存在
        if !Path::new(file_path).exists() {
            return Ok(UploadResult {
                success: false,
                remote_url: None,
                urn: None,
                error_message: Some("文件不存在".to_string()),
                file_size: 0,
            });
        }

        // 获取文件信息
        let file_metadata = fs::metadata(file_path).await?;
        let file_size = file_metadata.len();
        
        // 生成远程key
        let key = remote_key.unwrap_or_else(|| {
            self.generate_remote_key(file_path)
        });

        // 检测文件类型
        let content_type = self.detect_content_type(file_path);

        // 获取预签名URL
        let presign_response = match self.get_presign_url(&key, &content_type).await {
            Ok(response) => response,
            Err(e) => {
                return Ok(UploadResult {
                    success: false,
                    remote_url: None,
                    urn: None,
                    error_message: Some(format!("获取预签名URL失败: {}", e)),
                    file_size,
                });
            }
        };

        // 上传文件
        match self.upload_to_s3(&presign_response.url, file_path, &content_type, progress_callback).await {
            Ok(_) => {
                Ok(UploadResult {
                    success: true,
                    remote_url: Some(presign_response.urn.clone()),
                    urn: Some(presign_response.urn),
                    error_message: None,
                    file_size,
                })
            }
            Err(e) => {
                Ok(UploadResult {
                    success: false,
                    remote_url: None,
                    urn: None,
                    error_message: Some(format!("文件上传失败: {}", e)),
                    file_size,
                })
            }
        }
    }

    /// 批量上传文件
    pub async fn upload_files(
        &self,
        file_paths: Vec<String>,
        max_concurrent: Option<usize>,
        progress_callback: Option<Box<dyn Fn(usize, usize, &UploadResult) + Send + Sync>>,
    ) -> Result<Vec<UploadResult>> {
        let max_concurrent = max_concurrent.unwrap_or(3);
        let total_files = file_paths.len();

        // 使用信号量控制并发数
        let semaphore = std::sync::Arc::new(tokio::sync::Semaphore::new(max_concurrent));
        let mut handles = Vec::new();

        for (index, file_path) in file_paths.into_iter().enumerate() {
            let semaphore_clone = semaphore.clone();
            let service = self.clone();
            let callback = progress_callback.as_ref().map(|_| {
                // 为每个文件创建进度回调
                Box::new(move |_current: u64, _total: u64| {
                    // 单个文件的进度回调
                }) as ProgressCallback
            });

            let handle = tokio::spawn(async move {
                let permit = semaphore_clone.acquire().await.unwrap();
                let result = service.upload_file(&file_path, None, callback).await
                    .unwrap_or_else(|e| UploadResult {
                        success: false,
                        remote_url: None,
                        urn: None,
                        error_message: Some(e.to_string()),
                        file_size: 0,
                    });
                drop(permit); // 释放permit
                (index, result)
            });

            handles.push(handle);
        }

        // 等待所有上传完成
        let mut results = Vec::new();
        for handle in handles {
            let (index, result) = handle.await?;

            // 调用进度回调
            if let Some(callback) = &progress_callback {
                callback(index + 1, total_files, &result);
            }

            results.push((index, result));
        }

        // 按原始顺序排序结果
        results.sort_by_key(|(index, _)| *index);
        Ok(results.into_iter().map(|(_, result)| result).collect())
    }

    /// 获取预签名URL
    async fn get_presign_url(&self, key: &str, content_type: &str) -> Result<UploadPresignResponse> {
        let request = UploadPresignRequest {
            key: key.to_string(),
            content_type: content_type.to_string(),
        };

        let url = format!("{}/cache/upload-s3/simple/presign", self.base_url);
        
        let response = self.client
            .post(&url)
            .header("Authorization", format!("Bearer {}", self.bearer_token))
            .header("Content-Type", "application/json")
            .json(&request)
            .send()
            .await?;

        if !response.status().is_success() {
            let status = response.status();
            let text = response.text().await.unwrap_or_default();
            return Err(anyhow!("预签名请求失败: {} - {}", status, text));
        }

        let presign_response: UploadPresignResponse = response.json().await?;
        Ok(presign_response)
    }

    /// 上传文件到S3
    async fn upload_to_s3(
        &self,
        presign_url: &str,
        file_path: &str,
        content_type: &str,
        progress_callback: Option<ProgressCallback>,
    ) -> Result<()> {
        let file_data = fs::read(file_path).await?;
        let file_size = file_data.len() as u64;

        // 如果有进度回调，先调用开始上传
        if let Some(callback) = &progress_callback {
            callback(0, file_size);
        }

        let response = self.client
            .put(presign_url)
            .header("Content-Type", content_type)
            .body(file_data)
            .send()
            .await?;

        if !response.status().is_success() {
            let status = response.status();
            let text = response.text().await.unwrap_or_default();
            return Err(anyhow!("S3上传失败: {} - {}", status, text));
        }

        // 如果有进度回调，调用完成上传
        if let Some(callback) = &progress_callback {
            callback(file_size, file_size);
        }

        Ok(())
    }

    /// 生成远程文件key
    pub fn generate_remote_key(&self, file_path: &str) -> String {
        let path = Path::new(file_path);
        let file_name = path.file_name()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown");
        
        let timestamp = chrono::Utc::now().timestamp();
        let uuid = uuid::Uuid::new_v4().to_string();
        
        format!("templates/{}/{}/{}", timestamp, uuid, file_name)
    }

    /// 检测文件内容类型
    pub fn detect_content_type(&self, file_path: &str) -> String {
        let path = Path::new(file_path);
        let extension = path.extension()
            .and_then(|s| s.to_str())
            .unwrap_or("")
            .to_lowercase();

        match extension.as_str() {
            "mp4" | "mov" | "avi" | "mkv" | "webm" => "video/mp4",
            "mp3" | "wav" | "aac" | "flac" | "ogg" => "audio/mpeg",
            "jpg" | "jpeg" => "image/jpeg",
            "png" => "image/png",
            "gif" => "image/gif",
            "webp" => "image/webp",
            "pdf" => "application/pdf",
            "json" => "application/json",
            "txt" => "text/plain",
            _ => "application/octet-stream",
        }.to_string()
    }

    /// 获取基础URL（用于测试）
    pub fn get_base_url(&self) -> &str {
        &self.base_url
    }

    /// 获取Bearer令牌（用于测试）
    pub fn get_bearer_token(&self) -> &str {
        &self.bearer_token
    }

    /// 获取超时时间（用于测试）
    pub fn get_timeout(&self) -> Duration {
        self.timeout
    }
}

impl Clone for CloudUploadService {
    fn clone(&self) -> Self {
        Self {
            client: self.client.clone(),
            base_url: self.base_url.clone(),
            bearer_token: self.bearer_token.clone(),
            timeout: self.timeout,
        }
    }
}
