//! HTTP 请求处理器

use axum::{
    body::StreamBody,
    extract::{Multipart, Path, State},
    http::{header, StatusCode},
    response::{IntoResponse, Response},
    Json,
};
use dashmap::DashMap;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use tokio::sync::broadcast;
use tokio_util::io::ReaderStream;

use crate::models::{FileMetadata, TransferProgressEvent, TransferStatus};

/// 应用状态
#[derive(Clone)]
pub struct AppState {
    /// 待下载文件映射 (file_id -> 文件路径)
    pub files: Arc<DashMap<String, PathBuf>>,
    /// 文件元数据映射
    pub metadata: Arc<DashMap<String, FileMetadata>>,
    /// 进度事件发送器
    pub progress_tx: broadcast::Sender<TransferProgressEvent>,
    /// 下载目录
    pub download_dir: PathBuf,
    /// 本机设备 ID
    pub local_device_id: String,
}

impl AppState {
    /// 创建新的应用状态
    pub fn new(download_dir: PathBuf, local_device_id: String) -> Self {
        let (progress_tx, _) = broadcast::channel(100);
        Self {
            files: Arc::new(DashMap::new()),
            metadata: Arc::new(DashMap::new()),
            progress_tx,
            download_dir,
            local_device_id,
        }
    }

    /// 注册待下载文件
    pub fn register_file(&self, file_id: String, path: PathBuf, metadata: FileMetadata) {
        self.files.insert(file_id.clone(), path);
        self.metadata.insert(file_id, metadata);
    }

    /// 移除文件注册
    pub fn unregister_file(&self, file_id: &str) {
        self.files.remove(file_id);
        self.metadata.remove(file_id);
    }

    /// 获取进度事件订阅
    pub fn subscribe_progress(&self) -> broadcast::Receiver<TransferProgressEvent> {
        self.progress_tx.subscribe()
    }
}

/// 上传文件处理
/// POST /upload
pub async fn upload_handler(
    State(state): State<AppState>,
    mut multipart: Multipart,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    let mut file_id: Option<String> = None;
    let mut file_name: Option<String> = None;
    let mut _from_device: Option<String> = None;
    let mut saved_path: Option<PathBuf> = None;
    let mut total_size: u64 = 0;

    while let Some(field) = multipart
        .next_field()
        .await
        .map_err(|e| (StatusCode::BAD_REQUEST, format!("Multipart error: {}", e)))?
    {
        let name = field.name().unwrap_or("").to_string();

        match name.as_str() {
            "file_id" => {
                file_id = Some(
                    field
                        .text()
                        .await
                        .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?,
                );
            }
            "file_name" => {
                file_name = Some(
                    field
                        .text()
                        .await
                        .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?,
                );
            }
            "from_device" => {
                _from_device = Some(
                    field
                        .text()
                        .await
                        .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?,
                );
            }
            "file" => {
                let fname = file_name.clone().unwrap_or_else(|| {
                    field
                        .file_name()
                        .map(|s| s.to_string())
                        .unwrap_or_else(|| "unknown".to_string())
                });

                // 生成保存路径
                let save_path = state.download_dir.join(&fname);
                let mut file = File::create(&save_path)
                    .await
                    .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

                // 读取并写入文件内容
                let data = field
                    .bytes()
                    .await
                    .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;

                total_size = data.len() as u64;
                file.write_all(&data)
                    .await
                    .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

                file.flush()
                    .await
                    .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

                saved_path = Some(save_path);
                file_name = Some(fname);
            }
            _ => {}
        }
    }

    let file_id = file_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
    let file_name = file_name.ok_or((StatusCode::BAD_REQUEST, "Missing file name".to_string()))?;
    let saved_path =
        saved_path.ok_or((StatusCode::BAD_REQUEST, "No file uploaded".to_string()))?;
    let from_device = _from_device.unwrap_or_default();

    // 创建并保存传输记录（接收方）
    let transfer = crate::models::FileTransfer {
        file_id: file_id.clone(),
        name: file_name.clone(),
        size: total_size,
        progress: 1.0,
        status: TransferStatus::Completed,
        mime_type: mime_guess::from_path(&saved_path).first_or_octet_stream().to_string(),
        from_device: from_device.clone(),
        to_device: state.local_device_id.clone(),
        local_path: Some(saved_path.to_string_lossy().to_string()),
        created_at: chrono::Utc::now().timestamp(),
        completed_at: Some(chrono::Utc::now().timestamp()),
        transferred_bytes: total_size,
    };
    
    if let Err(e) = crate::database::Database::save_file_transfer(&transfer) {
        log::error!("Failed to save transfer record: {}", e);
    }

    // 发送完成事件（包含文件名和路径，供前端显示）
    let progress_event = TransferProgressEvent {
        file_id: file_id.clone(),
        progress: 1.0,
        transferred_bytes: total_size,
        total_bytes: total_size,
        status: TransferStatus::Completed,
        file_name: Some(file_name.clone()),
        local_path: Some(saved_path.to_string_lossy().to_string()),
    };
    let _ = state.progress_tx.send(progress_event);

    log::info!("File received: {} ({} bytes) from {}", file_name, total_size, from_device);

    Ok(Json(serde_json::json!({
        "success": true,
        "fileId": file_id,
        "fileName": file_name,
        "size": total_size,
        "path": saved_path.to_string_lossy()
    })))
}

/// 下载文件处理
/// GET /file/:id
pub async fn download_handler(
    State(state): State<AppState>,
    Path(file_id): Path<String>,
) -> Result<impl IntoResponse, (StatusCode, String)> {
    // 查找文件路径
    let file_path = state
        .files
        .get(&file_id)
        .map(|e| e.clone())
        .ok_or((StatusCode::NOT_FOUND, "File not found".to_string()))?;

    // 获取元数据
    let metadata = state.metadata.get(&file_id);

    // 打开文件
    let file = File::open(&file_path)
        .await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    let file_size = file
        .metadata()
        .await
        .map(|m| m.len())
        .unwrap_or(0);

    // 确定 MIME 类型
    let mime_type = metadata
        .as_ref()
        .map(|m| m.mime_type.clone())
        .unwrap_or_else(|| {
            mime_guess::from_path(&file_path)
                .first_or_octet_stream()
                .to_string()
        });

    // 确定文件名
    let file_name = metadata
        .as_ref()
        .map(|m| m.name.clone())
        .unwrap_or_else(|| {
            file_path
                .file_name()
                .map(|n| n.to_string_lossy().to_string())
                .unwrap_or_else(|| "download".to_string())
        });

    // 创建流式响应
    let stream = ReaderStream::new(file);
    let body = StreamBody::new(stream);

    let response = Response::builder()
        .status(StatusCode::OK)
        .header(header::CONTENT_TYPE, mime_type)
        .header(header::CONTENT_LENGTH, file_size)
        .header(
            header::CONTENT_DISPOSITION,
            format!("attachment; filename=\"{}\"", file_name),
        )
        .body(body)
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    log::info!("File download started: {}", file_name);

    Ok(response)
}

/// 获取文件元数据
/// GET /file/:id/info
pub async fn file_info_handler(
    State(state): State<AppState>,
    Path(file_id): Path<String>,
) -> Result<Json<FileMetadata>, (StatusCode, String)> {
    let metadata = state
        .metadata
        .get(&file_id)
        .map(|e| e.clone())
        .ok_or((StatusCode::NOT_FOUND, "File not found".to_string()))?;

    Ok(Json(metadata))
}

/// 健康检查
/// GET /health
pub async fn health_handler() -> Json<serde_json::Value> {
    Json(serde_json::json!({
        "status": "ok",
        "timestamp": chrono::Utc::now().timestamp()
    }))
}
