//! 文件传输相关命令

use std::path::PathBuf;
use tauri::{AppHandle, Emitter};
use tauri_plugin_dialog::DialogExt;
use tokio_util::sync::CancellationToken;

use crate::database::Database;
use crate::http::HttpServer;
use crate::models::{event_names, FileMetadata, FileTransfer, TransferStatus};
use crate::state::AppState;
use crate::utils::{AppConfig, CommandError, CommandResult};

/// 启动 HTTP 文件服务
#[tauri::command]
pub async fn start_http_server(app: AppHandle) -> CommandResult<()> {
    let state = AppState::get();
    let local_device = state.local_device.read().clone();
    let config = AppConfig::get();
    
    // 创建并启动 HTTP 服务
    let mut server = HttpServer::new(
        local_device.http_port,
        PathBuf::from(&config.download_dir),
        local_device.device_id.clone(),
    );
    
    server.start().await.map_err(|e| CommandError {
        code: "HTTP_SERVER_ERROR".to_string(),
        message: e.to_string(),
    })?;
    
    // 监听进度事件
    let mut rx = server.state().subscribe_progress();
    let app_handle = app.clone();
    
    tokio::spawn(async move {
        while let Ok(event) = rx.recv().await {
            let _ = app_handle.emit(event_names::TRANSFER_PROGRESS, &event);
            
            // 文件接收完成时发送事件
            if event.status == TransferStatus::Completed {
                let _ = app_handle.emit(event_names::FILE_RECEIVED, serde_json::json!({
                    "fileId": event.file_id,
                    "progress": event.progress,
                    "status": "completed"
                }));
            }
        }
    });
    
    *state.http_server.write() = Some(server);
    
    log::info!("HTTP server started on port {}", local_device.http_port);
    Ok(())
}

/// 停止 HTTP 文件服务
#[tauri::command]
pub async fn stop_http_server() -> CommandResult<()> {
    let state = AppState::get();
    
    if let Some(mut server) = state.http_server.write().take() {
        server.stop();
    }
    
    log::info!("HTTP server stopped");
    Ok(())
}

/// 选择要发送的文件
#[tauri::command]
pub async fn select_file_to_send(app: AppHandle) -> CommandResult<Option<FileMetadata>> {
    let file_path = app
        .dialog()
        .file()
        .blocking_pick_file();
    
    match file_path {
        Some(file_path) => {
            let path = file_path.into_path().map_err(|e| CommandError {
                code: "PATH_ERROR".to_string(),
                message: format!("Invalid file path: {}", e),
            })?;
            let file_name = path
                .file_name()
                .map(|n| n.to_string_lossy().to_string())
                .unwrap_or_else(|| "unknown".to_string());
            
            let metadata = std::fs::metadata(&path).map_err(|e| CommandError {
                code: "IO_ERROR".to_string(),
                message: e.to_string(),
            })?;
            
            let mime_type = mime_guess::from_path(&path)
                .first_or_octet_stream()
                .to_string();
            
            let file_id = uuid::Uuid::new_v4().to_string();
            
            // 注册文件供下载
            let state = AppState::get();
            if let Some(server) = state.http_server.read().as_ref() {
                server.register_file(
                    file_id.clone(),
                    path.clone(),
                    file_name.clone(),
                    metadata.len(),
                    mime_type.clone(),
                );
            }
            
            Ok(Some(FileMetadata {
                file_id,
                name: file_name,
                size: metadata.len(),
                mime_type,
                thumbnail: None,
                path: Some(path.to_string_lossy().to_string()),
            }))
        }
        None => Ok(None),
    }
}

/// 发送文件到指定设备
#[tauri::command]
pub async fn send_file(
    app: AppHandle,
    device_id: String,
    file_id: String,
    file_path: String,
) -> CommandResult<FileTransfer> {
    let state = AppState::get();
    let local_device = state.local_device.read().clone();
    
    // 获取目标设备
    let device = state
        .device_manager
        .get_device(&device_id)
        .ok_or_else(|| CommandError {
            code: "DEVICE_NOT_FOUND".to_string(),
            message: format!("Device {} not found", device_id),
        })?;
    
    log::info!("send_file called with file_id={}, file_path={}", file_id, file_path);
    
    // 优先从已注册的文件中获取路径（select_file_to_send 已经注册了文件）
    let (path, file_name, file_size, mime_type) = if let Some(server) = state.http_server.read().as_ref() {
        let server_state = server.state();
        if let Some(registered_path) = server_state.files.get(&file_id) {
            let p = registered_path.clone();
            let name = p.file_name()
                .map(|n| n.to_string_lossy().to_string())
                .unwrap_or_else(|| "unknown".to_string());
            let size = std::fs::metadata(&p).map(|m| m.len()).unwrap_or(0);
            let mime = mime_guess::from_path(&p).first_or_octet_stream().to_string();
            log::info!("Using registered file path: {:?}", p);
            (p, name, size, mime)
        } else {
            // 回退到前端传递的路径
            let p = PathBuf::from(&file_path);
            let name = p.file_name()
                .map(|n| n.to_string_lossy().to_string())
                .unwrap_or_else(|| "unknown".to_string());
            let size = std::fs::metadata(&p).map(|m| m.len()).unwrap_or(0);
            let mime = mime_guess::from_path(&p).first_or_octet_stream().to_string();
            log::info!("Using provided file path: {:?}", p);
            (p, name, size, mime)
        }
    } else {
        let p = PathBuf::from(&file_path);
        let name = p.file_name()
            .map(|n| n.to_string_lossy().to_string())
            .unwrap_or_else(|| "unknown".to_string());
        let size = std::fs::metadata(&p).map(|m| m.len()).unwrap_or(0);
        let mime = mime_guess::from_path(&p).first_or_octet_stream().to_string();
        (p, name, size, mime)
    };
    
    log::info!("Resolved file_name={}, file_size={}", file_name, file_size);
    
    // 创建传输记录
    let transfer = FileTransfer::new_outgoing(
        file_name,
        file_size,
        mime_type,
        local_device.device_id.clone(),
        device_id.clone(),
        path.to_string_lossy().to_string(),
    );
    
    // 保存到数据库
    Database::save_file_transfer(&transfer).map_err(|e| CommandError {
        code: "DB_ERROR".to_string(),
        message: e.to_string(),
    })?;
    
    // 设置 AppHandle 用于发送进度事件
    state.http_client.set_app_handle(app.clone());
    
    // 创建取消 token
    let cancel_token = CancellationToken::new();
    {
        let mut tokens = state.transfer_cancellation_tokens.write();
        tokens.insert(transfer.file_id.clone(), cancel_token.clone());
    }
    
    // 执行上传（使用 transfer.file_id 保持一致）
    let transfer_clone = transfer.clone();
    let transfer_file_id = transfer.file_id.clone();
    let transfer_file_id_for_cleanup = transfer.file_id.clone();
    let http_client = state.http_client.clone();
    let device_clone = device.clone();
    let local_device_id = local_device.device_id.clone();
    let state_clone = state.clone();
    
    tokio::spawn(async move {
        let result = http_client
            .upload_file(&device_clone, &path, &transfer_file_id, &local_device_id, cancel_token)
            .await;
        
        // 清理取消 token
        {
            let mut tokens = state_clone.transfer_cancellation_tokens.write();
            tokens.remove(&transfer_file_id_for_cleanup);
        }
        
        if let Err(e) = result {
            log::error!("File upload failed: {}", e);
        }
    });
    
    Ok(transfer_clone)
}

/// 取消文件传输
#[tauri::command]
pub async fn cancel_transfer(file_id: String) -> CommandResult<()> {
    log::info!("Cancelling transfer: {}", file_id);
    
    let state = AppState::get();
    
    // 触发取消 token
    {
        let tokens = state.transfer_cancellation_tokens.read();
        if let Some(token) = tokens.get(&file_id) {
            token.cancel();
            log::info!("Cancelled transfer token for: {}", file_id);
        }
    }
    
    // 更新数据库中的传输状态
    Database::update_transfer_status(&file_id, "cancelled").map_err(|e| CommandError {
        code: "DB_ERROR".to_string(),
        message: e.to_string(),
    })?;
    
    Ok(())
}

/// 获取文件传输历史
#[tauri::command]
pub async fn get_transfer_history(
    device_id: String,
    limit: Option<usize>,
) -> CommandResult<Vec<FileTransfer>> {
    let state = AppState::get();
    let local_device = state.local_device.read();
    
    let transfers = Database::get_transfer_history(
        &device_id,
        &local_device.device_id,
        limit.unwrap_or(50),
    )
    .map_err(|e| CommandError {
        code: "DB_ERROR".to_string(),
        message: e.to_string(),
    })?;
    
    Ok(transfers)
}

/// 在文件管理器中打开文件位置
#[tauri::command]
pub async fn open_file_location(path: String) -> CommandResult<()> {
    let path = PathBuf::from(&path);
    
    // 获取父目录
    let _dir = path.parent().unwrap_or(&path);
    
    #[cfg(target_os = "windows")]
    {
        std::process::Command::new("explorer")
            .arg("/select,")
            .arg(&path)
            .spawn()
            .map_err(|e| CommandError {
                code: "IO_ERROR".to_string(),
                message: e.to_string(),
            })?;
    }
    
    #[cfg(target_os = "macos")]
    {
        std::process::Command::new("open")
            .arg("-R")
            .arg(&path)
            .spawn()
            .map_err(|e| CommandError {
                code: "IO_ERROR".to_string(),
                message: e.to_string(),
            })?;
    }
    
    #[cfg(target_os = "linux")]
    {
        std::process::Command::new("xdg-open")
            .arg(dir)
            .spawn()
            .map_err(|e| CommandError {
                code: "IO_ERROR".to_string(),
                message: e.to_string(),
            })?;
    }
    
    Ok(())
}
