//! Voice 音频管理 IPC 命令

use crate::ApiResponse;
use crate::storage::voice as voice_storage;
use tauri::Manager;

// --------------------- 音色素材库命令 ---------------------

#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VoiceMaterialArgs {
    pub id: String,
    pub name: String,
    pub voice_id: String,
    pub source_url: String,
    pub trial_url: Option<String>,
    pub status: String,
    pub created_at: String,
}

/// 加载音色素材库
#[tauri::command]
pub async fn load_voice_materials(
    app: tauri::AppHandle,
) -> ApiResponse<Vec<voice_storage::VoiceMaterial>> {
    let user_id = match crate::storage::auth::get_current_user_id(&app) {
        Ok(Some(id)) => id,
        Ok(None) => return ApiResponse {
            code: 401,
            message: "未登录".to_string(),
            data: Some(vec![]),
        },
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取用户信息失败: {}", e),
            data: Some(vec![]),
        },
    };

    match voice_storage::load_voice_materials(&user_id) {
        Ok(list) => ApiResponse {
            code: 200,
            message: "素材库加载成功".to_string(),
            data: Some(list.materials),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("加载素材库失败: {}", e),
            data: Some(vec![]),
        },
    }
}

/// 保存音色素材
#[tauri::command]
pub async fn save_voice_material(
    app: tauri::AppHandle,
    args: VoiceMaterialArgs,
) -> ApiResponse<bool> {
    let user_id = match crate::storage::auth::get_current_user_id(&app) {
        Ok(Some(id)) => id,
        Ok(None) => return ApiResponse {
            code: 401,
            message: "未登录".to_string(),
            data: Some(false),
        },
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取用户信息失败: {}", e),
            data: Some(false),
        },
    };

    let material = voice_storage::VoiceMaterial {
        id: args.id,
        name: args.name,
        voice_id: args.voice_id,
        source_url: args.source_url,
        trial_url: args.trial_url,
        status: args.status,
        created_at: args.created_at,
    };
    match voice_storage::add_voice_material(&user_id, material) {
        Ok(_) => ApiResponse {
            code: 200,
            message: "素材保存成功".to_string(),
            data: Some(true),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("保存素材失败: {}", e),
            data: Some(false),
        },
    }
}

/// 删除音色素材
#[tauri::command]
pub async fn delete_voice_material_cmd(
    app: tauri::AppHandle,
    id: String,
) -> ApiResponse<bool> {
    let user_id = match crate::storage::auth::get_current_user_id(&app) {
        Ok(Some(id)) => id,
        Ok(None) => return ApiResponse {
            code: 401,
            message: "未登录".to_string(),
            data: Some(false),
        },
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取用户信息失败: {}", e),
            data: Some(false),
        },
    };

    match voice_storage::delete_voice_material(&user_id, &id) {
        Ok(_) => ApiResponse {
            code: 200,
            message: "素材删除成功".to_string(),
            data: Some(true),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("删除素材失败: {}", e),
            data: Some(false),
        },
    }
}

// --------------------- 音频文件命令 ---------------------

#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SaveAudioArgs {
    pub project_id: String,
    pub audio_id: String,
    pub audio_data: String,
    pub name: String,
    pub voice_id: String,
    pub duration: f64,
}

/// 保存音频文件（前端传入 base64 编码）
#[tauri::command]
pub async fn save_audio(
    app: tauri::AppHandle,
    args: SaveAudioArgs,
) -> ApiResponse<voice_storage::AudioMeta> {
    let user_id = match crate::storage::auth::get_current_user_id(&app) {
        Ok(Some(id)) => id,
        Ok(None) => return ApiResponse {
            code: 401,
            message: "未登录".to_string(),
            data: None,
        },
        Err(e) => return ApiResponse {
            code: 500,
            message: format!("获取用户信息失败: {}", e),
            data: None,
        },
    };

    let audio_bytes = match base64::Engine::decode(
        &base64::engine::general_purpose::STANDARD,
        &args.audio_data,
    ) {
        Ok(data) => data,
        Err(e) => return ApiResponse {
            code: 400,
            message: format!("Invalid base64 data: {}", e),
            data: None,
        },
    };

    match voice_storage::save_audio_file(
        &user_id,
        &args.project_id,
        &args.audio_id,
        &audio_bytes,
        &args.name,
        &args.voice_id,
        args.duration,
    ) {
        Ok(meta) => ApiResponse {
            code: 200,
            message: "Audio saved successfully".to_string(),
            data: Some(meta),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("Failed to save audio: {}", e),
            data: None,
        },
    }
}

// --------------------- 音频截取与上传 ---------------------

#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExtractAudioSegmentArgs {
    pub input_path: String,
    pub start: f64,
    pub duration: f64,
    pub output_path: String,
}

/// 截取音频片段（FFmpeg）
#[tauri::command]
pub async fn extract_audio_segment(
    app: tauri::AppHandle,
    args: ExtractAudioSegmentArgs,
) -> ApiResponse<String> {
    match crate::ffmpeg_cmd::extract_audio_segment(
        &app,
        &args.input_path,
        args.start,
        args.duration,
        &args.output_path,
    ).await {
        Ok(_) => ApiResponse {
            code: 200,
            message: "Audio segment extracted successfully".to_string(),
            data: Some(args.output_path),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("Failed to extract audio segment: {}", e),
            data: None,
        },
    }
}

/**
 * 从本地视频文件中提取音频（MP4 → MP3）
 *
 * 输出文件自动生成在 app_local_data_dir/temp/ 下。
 * @param input_path 本地视频文件路径（需在 app_local_data_dir 下）
 * @returns 提取后的 MP3 文件路径
 */
#[tauri::command]
pub async fn extract_audio_from_video(
    app: tauri::AppHandle,
    input_path: String,
) -> ApiResponse<String> {
    // 验证输入路径安全
    let safe_input = match crate::ffmpeg_cmd::sanitize_output_path(&input_path) {
        Ok(p) => p,
        Err(e) => {
            return ApiResponse {
                code: 500,
                message: format!("路径验证失败: {}", e),
                data: None,
            };
        }
    };

    // 生成输出路径：app_local_data_dir/temp/extracted_{uuid}.mp3
    let output_path = match app.path().app_local_data_dir() {
        Ok(dir) => {
            let temp_dir = dir.join("temp");
            if let Err(e) = std::fs::create_dir_all(&temp_dir) {
                return ApiResponse {
                    code: 500,
                    message: format!("创建临时目录失败: {}", e),
                    data: None,
                };
            }
            temp_dir.join(format!("extracted_{}.mp3", uuid::Uuid::new_v4()))
        }
        Err(e) => {
            return ApiResponse {
                code: 500,
                message: format!("获取应用目录失败: {}", e),
                data: None,
            };
        }
    };

    match crate::ffmpeg_cmd::extract_audio_from_video(
        &app,
        &safe_input,
        &output_path.to_string_lossy(),
    ).await {
        Ok(_) => ApiResponse {
            code: 200,
            message: "音频提取成功".to_string(),
            data: Some(output_path.to_string_lossy().to_string()),
        },
        Err(e) => ApiResponse {
            code: 500,
            message: format!("音频提取失败: {}", e),
            data: None,
        },
    }
}

/// 上传本地音频文件到后端，后端上传到七牛云并返回 URL
#[tauri::command]
pub async fn upload_audio_file(
    app: tauri::AppHandle,
    local_path: String,
) -> ApiResponse<crate::commands::video_compose::UploadVideoResult> {
    // 验证路径安全
    let safe_path = match crate::ffmpeg_cmd::sanitize_output_path(&local_path) {
        Ok(p) => p,
        Err(e) => {
            return ApiResponse {
                code: 500,
                message: format!("路径验证失败: {}", e),
                data: None,
            };
        }
    };

    crate::commands::video_compose::upload_file_to_backend(
        &app,
        &safe_path,
        "/upload/audio",
        "audio.mp3",
        "audio/mpeg",
        "读取音频文件失败",
    ).await
}
