//! 成品保存命令
//!
//! 每个项目的成品保存在各自目录下：{app_local_data_dir}/projects/{id}/products/
//! 成品与项目的关联通过目录结构天然建立，无需从文件名解析 project_id。

use crate::ApiResponse;
use crate::storage::get_project_products_dir;
use crate::storage::sanitize_filename;
use std::fs;
use serde::Serialize;
use std::path::PathBuf;
use tauri::AppHandle;

#[derive(Serialize)]
pub struct ProductItem {
    pub filename: String,
    pub path: String,
    pub created_at: u64,
    pub file_size: u64,
    pub duration: f64,
    pub poster_path: Option<String>,
}

/// 获取成品保存路径（项目成品目录）
#[tauri::command]
pub async fn get_product_save_path(project_id: String, filename: String) -> ApiResponse<String> {
    match get_project_products_dir(&project_id) {
        Ok(products_dir) => {
            let safe_filename = match sanitize_filename(&filename) {
                Ok(name) => name,
                Err(e) => {
                    return ApiResponse {
                        code: 500,
                        message: format!("文件名验证失败: {}", e),
                        data: None,
                    };
                }
            };
            let target_path = products_dir.join(&safe_filename);
            ApiResponse {
                code: 200,
                message: "获取路径成功".to_string(),
                data: Some(target_path.to_string_lossy().to_string()),
            }
        }
        Err(e) => ApiResponse {
            code: 500,
            message: format!("获取成品目录失败: {}", e),
            data: None,
        },
    }
}

#[tauri::command]
pub async fn list_local_products(_app: AppHandle) -> ApiResponse<Vec<ProductItem>> {
    let projects_root = match crate::storage::get_projects_root_dir() {
        Ok(dir) => dir,
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取项目根目录失败: {}", e),
            data: None,
        },
    };

    if !projects_root.exists() {
        return ApiResponse {
            code: 200,
            message: "成功".to_string(),
            data: Some(vec![]),
        };
    }

    let mut products = Vec::new();

    let projects_iter = match fs::read_dir(&projects_root) {
        Ok(iter) => iter,
        Err(_) => return ApiResponse {
            code: 200,
            message: "成功".to_string(),
            data: Some(vec![]),
        },
    };

    for project_entry in projects_iter {
        let project_entry = match project_entry {
            Ok(e) => e,
            Err(_) => continue,
        };

        let project_dir = project_entry.path();
        if !project_dir.is_dir() {
            continue;
        }

        // 读取项目 meta.json 获取封面和时长
        let meta_path = project_dir.join("meta.json");
        let (cover_path, duration) = match fs::read_to_string(&meta_path) {
            Ok(content) => match serde_json::from_str::<serde_json::Value>(&content) {
                Ok(meta) => {
                    let cover = meta.get("coverPath").and_then(|v| v.as_str()).map(|s| s.to_string());
                    let dur = meta.get("finalVideoDuration").and_then(|v| v.as_f64()).unwrap_or(0.0);
                    (cover, dur)
                }
                Err(_) => (None, 0.0),
            }
            Err(_) => (None, 0.0),
        };

        let products_dir = project_dir.join("products");
        if !products_dir.exists() {
            continue;
        }

        let products_iter = match fs::read_dir(&products_dir) {
            Ok(iter) => iter,
            Err(_) => continue,
        };

        for entry in products_iter {
            let entry = match entry {
                Ok(e) => e,
                Err(_) => continue,
            };

            let path = entry.path();
            if !path.is_file() {
                continue;
            }

            // 只处理视频文件
            let ext = path.extension()
                .and_then(|e| e.to_str())
                .map(|e| e.to_lowercase());
            match ext {
                Some(ext) if ["mp4", "mov", "avi", "mkv", "webm"].contains(&ext.as_str()) => {}
                _ => continue,
            }

            let filename = entry.file_name().to_string_lossy().to_string();
            let path_str = path.to_string_lossy().to_string();

            let metadata = match entry.metadata() {
                Ok(md) => md,
                Err(_) => continue,
            };

            let created_at_sys = match metadata.created() {
                Ok(ct) => ct,
                Err(_) => match metadata.modified() {
                    Ok(mt) => mt,
                    Err(_) => std::time::SystemTime::UNIX_EPOCH,
                }
            };

            let created_at = created_at_sys
                .duration_since(std::time::UNIX_EPOCH)
                .unwrap_or_default()
                .as_millis() as u64;

            let file_size = metadata.len();

            // 封面路径：检查 meta.json 中的 coverPath 是否存在
            let poster_path_str = cover_path.as_ref().and_then(|cp| {
                let cp_path = PathBuf::from(cp);
                if cp_path.exists() {
                    Some(cp.clone())
                } else {
                    None
                }
            });

            products.push(ProductItem {
                filename,
                path: path_str,
                created_at,
                file_size,
                duration,
                poster_path: poster_path_str,
            });
        }
    }

    // 按创建时间倒序排序，最新的在前
    products.sort_by(|a, b| b.created_at.cmp(&a.created_at));

    ApiResponse {
        code: 200,
        message: "成功".to_string(),
        data: Some(products),
    }
}

#[tauri::command]
pub async fn delete_local_product(path: String) -> ApiResponse<()> {
    let target = PathBuf::from(&path);

    // 安全检查：确保路径在应用数据目录内
    let canonical = match target.canonicalize() {
        Ok(p) => p,
        Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
            return ApiResponse {
                code: 200,
                message: "文件不存在".to_string(),
                data: Some(()),
            };
        }
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("路径解析失败: {}", e),
            data: None,
        },
    };

    let app_data = match crate::storage::get_app_data_dir() {
        Ok(dir) => dir,
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取应用数据目录失败: {}", e),
            data: None,
        },
    };
    let app_data_canonical = app_data.canonicalize().unwrap_or_else(|_| app_data.clone());

    if !canonical.starts_with(&app_data_canonical) {
        return ApiResponse {
            code: 400,
            message: "路径不在允许范围内".to_string(),
            data: None,
        };
    }

    if target.exists() && target.is_file() {
        match fs::remove_file(&target) {
            Ok(_) => ApiResponse {
                code: 200,
                message: "删除成功".to_string(),
                data: Some(()),
            },
            Err(e) => ApiResponse {
                code: 500,
                message: format!("删除失败: {}", e),
                data: None,
            },
        }
    } else {
        ApiResponse {
            code: 404,
            message: "文件不存在".to_string(),
            data: None,
        }
    }
}

#[tauri::command]
pub async fn rename_local_product(path: String, new_filename: String) -> ApiResponse<()> {
    let old_path = PathBuf::from(&path);

    // 安全检查
    let canonical = match old_path.canonicalize() {
        Ok(p) => p,
        Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
            return ApiResponse {
                code: 404,
                message: "原文件不存在".to_string(),
                data: None,
            };
        }
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("路径解析失败: {}", e),
            data: None,
        },
    };

    let app_data = match crate::storage::get_app_data_dir() {
        Ok(dir) => dir,
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取应用数据目录失败: {}", e),
            data: None,
        },
    };
    let app_data_canonical = app_data.canonicalize().unwrap_or_else(|_| app_data.clone());

    if !canonical.starts_with(&app_data_canonical) {
        return ApiResponse {
            code: 400,
            message: "路径不在允许范围内".to_string(),
            data: None,
        };
    }

    let parent = match old_path.parent() {
        Some(p) => p.to_path_buf(),
        None => return ApiResponse {
            code: 400,
            message: "无效的文件路径".to_string(),
            data: None,
        },
    };

    let new_path = parent.join(&new_filename);

    if new_path.exists() {
        return ApiResponse {
            code: 400,
            message: "文件名已存在".to_string(),
            data: None,
        };
    }

    // 检查扩展名
    let old_ext = old_path.extension()
        .and_then(|e| e.to_str())
        .map(|e| e.to_lowercase());
    let new_ext = new_path.extension()
        .and_then(|e| e.to_str())
        .map(|e| e.to_lowercase());

    let final_new_path = if new_ext != old_ext && old_ext.is_some() {
        new_path.with_extension(old_ext.unwrap())
    } else {
        new_path
    };

    match fs::rename(&old_path, &final_new_path) {
        Ok(_) => ApiResponse {
            code: 200,
            message: "重命名成功".to_string(),
            data: Some(()),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("重命名失败: {}", e),
            data: None,
        },
    }
}

/// 导出成品到用户指定位置
#[tauri::command]
pub async fn export_product(source_path: String, target_path: String) -> ApiResponse<String> {
    let source = PathBuf::from(&source_path);
    let target = PathBuf::from(&target_path);

    // 安全检查：source 必须在应用数据目录内
    let source_canonical = match source.canonicalize() {
        Ok(p) => p,
        Err(e) => return ApiResponse {
            code: 404,
            message: format!("源文件不存在: {}", e),
            data: None,
        },
    };

    let app_data = match crate::storage::get_app_data_dir() {
        Ok(dir) => dir,
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取应用数据目录失败: {}", e),
            data: None,
        },
    };
    let app_data_canonical = app_data.canonicalize().unwrap_or_else(|_| app_data.clone());

    if !source_canonical.starts_with(&app_data_canonical) {
        return ApiResponse {
            code: 400,
            message: "源文件不在允许范围内".to_string(),
            data: None,
        };
    }

    if !source.exists() || !source.is_file() {
        return ApiResponse {
            code: 404,
            message: "源文件不存在".to_string(),
            data: None,
        };
    }

    // 自动创建目标目录
    if let Some(parent) = target.parent() {
        if let Err(e) = std::fs::create_dir_all(parent) {
            return ApiResponse {
                code: 500,
                message: format!("创建目标目录失败: {}", e),
                data: None,
            };
        }
    }

    match std::fs::copy(&source, &target) {
        Ok(_) => ApiResponse {
            code: 200,
            message: "导出成功".to_string(),
            data: Some(target.to_string_lossy().to_string()),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("导出失败: {}", e),
            data: None,
        },
    }
}
