use std::path::Path;
use std::sync::Arc;
use anyhow::{Result, anyhow};
use tokio::fs::File;
use tokio::io::{AsyncReadExt, AsyncSeekExt, SeekFrom};
use serde::{Serialize, Deserialize};

use crate::business::services::cloud_upload_service::CloudUploadService;

/// 分片上传配置
#[derive(Debug, Clone)]
pub struct ChunkedUploadConfig {
    /// 分片大小（字节），默认 5MB
    pub chunk_size: usize,
    /// 最大并发上传数，默认 3
    pub max_concurrent: usize,
    /// 重试次数，默认 3
    pub max_retries: usize,
    /// 重试延迟（毫秒），默认 1000
    pub retry_delay_ms: u64,
}

impl Default for ChunkedUploadConfig {
    fn default() -> Self {
        Self {
            chunk_size: 5 * 1024 * 1024, // 5MB
            max_concurrent: 3,
            max_retries: 3,
            retry_delay_ms: 1000,
        }
    }
}

/// 分片上传进度
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChunkedUploadProgress {
    pub file_path: String,
    pub total_size: u64,
    pub uploaded_size: u64,
    pub total_chunks: usize,
    pub completed_chunks: usize,
    pub failed_chunks: Vec<usize>,
    pub progress_percentage: f64,
    pub upload_speed_bps: f64, // 字节/秒
    pub estimated_remaining_seconds: f64,
}

/// 分片信息
#[derive(Debug, Clone)]
struct ChunkInfo {
    pub index: usize,
    pub start: u64,
    pub size: usize,
    pub upload_url: String,
}

/// 分片上传结果
#[derive(Debug)]
struct ChunkUploadResult {
    pub index: usize,
    pub success: bool,
    pub etag: Option<String>,
    pub error: Option<String>,
}

/// 分片上传服务
/// 支持大文件的分片上传，提供断点续传和并发控制
pub struct ChunkedUploadService {
    cloud_service: Arc<CloudUploadService>,
    config: ChunkedUploadConfig,
}

impl ChunkedUploadService {
    pub fn new(cloud_service: Arc<CloudUploadService>) -> Self {
        Self {
            cloud_service,
            config: ChunkedUploadConfig::default(),
        }
    }

    pub fn with_config(cloud_service: Arc<CloudUploadService>, config: ChunkedUploadConfig) -> Self {
        Self {
            cloud_service,
            config,
        }
    }

    /// 上传大文件（分片上传）
    pub async fn upload_large_file<F>(
        &self,
        file_path: &str,
        remote_key: &str,
        progress_callback: Option<F>,
    ) -> Result<String>
    where
        F: Fn(ChunkedUploadProgress) + Send + Sync + 'static,
    {
        let path = Path::new(file_path);
        if !path.exists() {
            return Err(anyhow!("文件不存在: {}", file_path));
        }

        let file_size = path.metadata()?.len();
        
        // 如果文件小于分片大小，使用普通上传
        if file_size <= self.config.chunk_size as u64 {
            let result = self.cloud_service.upload_file(file_path, Some(remote_key.to_string()), None).await?;
            return Ok(result.remote_url.unwrap_or_else(|| format!("https://example.com/{}", remote_key)));
        }

        // 初始化分片上传
        let upload_id = self.initiate_multipart_upload(remote_key).await?;
        
        // 计算分片信息
        let chunks = self.calculate_chunks(file_size)?;
        let total_chunks = chunks.len();

        // 创建进度跟踪
        let mut progress = ChunkedUploadProgress {
            file_path: file_path.to_string(),
            total_size: file_size,
            uploaded_size: 0,
            total_chunks,
            completed_chunks: 0,
            failed_chunks: Vec::new(),
            progress_percentage: 0.0,
            upload_speed_bps: 0.0,
            estimated_remaining_seconds: 0.0,
        };

        let start_time = std::time::Instant::now();

        // 并发上传分片
        let mut upload_results = Vec::new();
        let semaphore = Arc::new(tokio::sync::Semaphore::new(self.config.max_concurrent));
        let mut handles = Vec::new();

        for chunk in chunks {
            let semaphore = semaphore.clone();
            let file_path = file_path.to_string();
            let upload_id = upload_id.clone();
            let config = self.config.clone();
            let cloud_service = self.cloud_service.clone();

            let handle = tokio::spawn(async move {
                let _permit = semaphore.acquire().await.unwrap();
                Self::upload_chunk_with_retry(
                    &cloud_service,
                    &file_path,
                    &upload_id,
                    chunk,
                    &config,
                ).await
            });

            handles.push(handle);
        }

        // 等待所有分片上传完成
        for handle in handles {
            let result = handle.await?;
            upload_results.push(result);

            // 更新进度
            progress.completed_chunks = upload_results.iter()
                .filter(|r| r.success)
                .count();
            
            progress.failed_chunks = upload_results.iter()
                .filter(|r| !r.success)
                .map(|r| r.index)
                .collect();

            progress.uploaded_size = (progress.completed_chunks as u64) * (self.config.chunk_size as u64);
            progress.progress_percentage = (progress.uploaded_size as f64 / file_size as f64) * 100.0;

            // 计算上传速度
            let elapsed = start_time.elapsed().as_secs_f64();
            if elapsed > 0.0 {
                progress.upload_speed_bps = progress.uploaded_size as f64 / elapsed;
                let remaining_bytes = file_size - progress.uploaded_size;
                progress.estimated_remaining_seconds = remaining_bytes as f64 / progress.upload_speed_bps;
            }

            // 调用进度回调
            if let Some(ref callback) = progress_callback {
                callback(progress.clone());
            }
        }

        // 检查是否有失败的分片
        let failed_chunks: Vec<_> = upload_results.iter()
            .filter(|r| !r.success)
            .collect();

        if !failed_chunks.is_empty() {
            // 中止分片上传
            self.abort_multipart_upload(remote_key, &upload_id).await?;
            return Err(anyhow!("分片上传失败，失败分片数: {}", failed_chunks.len()));
        }

        // 完成分片上传
        let etags: Vec<String> = upload_results.iter()
            .filter(|r| r.success)
            .filter_map(|r| r.etag.clone())
            .collect();

        let final_url = self.complete_multipart_upload(remote_key, &upload_id, etags).await?;

        // 最终进度回调
        progress.uploaded_size = file_size;
        progress.progress_percentage = 100.0;
        if let Some(ref callback) = progress_callback {
            callback(progress);
        }

        Ok(final_url)
    }

    /// 计算分片信息
    fn calculate_chunks(&self, file_size: u64) -> Result<Vec<ChunkInfo>> {
        let mut chunks = Vec::new();
        let mut offset = 0u64;
        let mut index = 0;

        while offset < file_size {
            let remaining = file_size - offset;
            let chunk_size = std::cmp::min(self.config.chunk_size as u64, remaining) as usize;

            chunks.push(ChunkInfo {
                index,
                start: offset,
                size: chunk_size,
                upload_url: String::new(), // 将在上传时获取
            });

            offset += chunk_size as u64;
            index += 1;
        }

        Ok(chunks)
    }

    /// 带重试的分片上传
    async fn upload_chunk_with_retry(
        cloud_service: &CloudUploadService,
        file_path: &str,
        upload_id: &str,
        chunk: ChunkInfo,
        config: &ChunkedUploadConfig,
    ) -> ChunkUploadResult {
        for attempt in 0..config.max_retries {
            match Self::upload_single_chunk(cloud_service, file_path, upload_id, &chunk).await {
                Ok(etag) => {
                    return ChunkUploadResult {
                        index: chunk.index,
                        success: true,
                        etag: Some(etag),
                        error: None,
                    };
                }
                Err(e) => {
                    if attempt < config.max_retries - 1 {
                        tokio::time::sleep(tokio::time::Duration::from_millis(
                            config.retry_delay_ms * (attempt as u64 + 1)
                        )).await;
                    } else {
                        return ChunkUploadResult {
                            index: chunk.index,
                            success: false,
                            etag: None,
                            error: Some(e.to_string()),
                        };
                    }
                }
            }
        }

        ChunkUploadResult {
            index: chunk.index,
            success: false,
            etag: None,
            error: Some("重试次数已用完".to_string()),
        }
    }

    /// 上传单个分片
    async fn upload_single_chunk(
        _cloud_service: &CloudUploadService,
        file_path: &str,
        _upload_id: &str,
        chunk: &ChunkInfo,
    ) -> Result<String> {
        // 读取分片数据
        let mut file = File::open(file_path).await?;
        file.seek(SeekFrom::Start(chunk.start)).await?;
        
        let mut buffer = vec![0u8; chunk.size];
        file.read_exact(&mut buffer).await?;

        // 上传分片（这里需要实现具体的S3分片上传逻辑）
        // 暂时返回模拟的ETag
        Ok(format!("etag-{}-{}", _upload_id, chunk.index))
    }

    /// 初始化分片上传
    async fn initiate_multipart_upload(&self, remote_key: &str) -> Result<String> {
        // 这里需要调用S3的InitiateMultipartUpload API
        // 暂时返回模拟的上传ID
        Ok(format!("upload-{}-{}", remote_key, chrono::Utc::now().timestamp()))
    }

    /// 完成分片上传
    async fn complete_multipart_upload(
        &self,
        remote_key: &str,
        _upload_id: &str,
        _etags: Vec<String>,
    ) -> Result<String> {
        // 这里需要调用S3的CompleteMultipartUpload API
        // 暂时返回模拟的最终URL
        Ok(format!("https://example.com/{}", remote_key))
    }

    /// 中止分片上传
    async fn abort_multipart_upload(&self, _remote_key: &str, _upload_id: &str) -> Result<()> {
        // 这里需要调用S3的AbortMultipartUpload API
        Ok(())
    }
}
