//! Voice 音频文件存储模块
//!
//! 管理 TTS 合成音频文件的本地存储。

use serde::{Deserialize, Serialize};
use std::path::PathBuf;

use crate::storage::engine::{atomic_write_bytes, read_json, ensure_dir, StorageError};
use crate::storage::paths::get_project_dir;

/// 音频文件元数据
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AudioMeta {
    pub id: String,
    pub name: String,
    pub file_path: String,
    pub duration: f64,
    pub file_size: u64,
    pub voice_id: String,
    pub created_at: String,
    pub segment_id: Option<String>,
}

/// 保存音频文件到项目目录
///
/// 将 base64 编码的音频数据写入 `audios/` 子目录。
pub fn save_audio_file(
    project_id: &str,
    audio_id: &str,
    data: &[u8],
    name: &str,
    voice_id: &str,
    duration: f64,
) -> Result<AudioMeta, StorageError> {
    let project_dir = get_project_dir(project_id)?;
    let audios_dir = project_dir.join("audios");
    ensure_dir(&audios_dir)?;

    let extension = "mp3";
    let file_name = format!("{}.{}", audio_id, extension);
    let file_path = audios_dir.join(&file_name);

    atomic_write_bytes(&file_path, data)?;

    let meta = AudioMeta {
        id: audio_id.to_string(),
        name: name.to_string(),
        file_path: file_path.to_str().unwrap_or_default().to_string(),
        duration,
        file_size: data.len() as u64,
        voice_id: voice_id.to_string(),
        created_at: chrono_lite_now(),
        segment_id: None,
    };

    Ok(meta)
}

// ====================== 工具函数 ======================

fn chrono_lite_now() -> String {
    chrono::Utc::now().to_rfc3339()
}

// ====================== 私有音色素材库 ======================

/// 音色素材记录
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VoiceMaterial {
    pub id: String,
    pub name: String,
    pub voice_id: String,
    pub source_url: String,
    pub trial_url: Option<String>,
    pub status: String, // pending / processing / ready / failed
    pub created_at: String,
}

/// 音色素材库列表
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct VoiceMaterialsList {
    pub materials: Vec<VoiceMaterial>,
    pub updated_at: String,
}

/// 加载音色素材库
pub fn load_voice_materials() -> Result<VoiceMaterialsList, StorageError> {
    let path = crate::storage::paths::get_voices_json_path()?;
    Ok(read_json(&path)?.unwrap_or_default())
}

/// 保存音色素材库
pub fn save_voice_materials(list: &VoiceMaterialsList) -> Result<(), StorageError> {
    let path = crate::storage::paths::get_voices_json_path()?;
    crate::storage::engine::atomic_write_json(&path, list)
}

/// 添加音色素材
pub fn add_voice_material(material: VoiceMaterial) -> Result<(), StorageError> {
    let mut list = load_voice_materials()?;
    // 去重：相同 id 替换
    if let Some(pos) = list.materials.iter().position(|m| m.id == material.id) {
        list.materials[pos] = material;
    } else {
        list.materials.push(material);
    }
    list.updated_at = chrono_lite_now();
    save_voice_materials(&list)
}

/// 删除音色素材
pub fn delete_voice_material(id: &str) -> Result<(), StorageError> {
    let mut list = load_voice_materials()?;
    let pos = list.materials.iter().position(|m| m.id == id)
        .ok_or_else(|| StorageError::Io(std::io::Error::new(
            std::io::ErrorKind::NotFound,
            format!("音色素材 {} 不存在", id),
        )))?;
    list.materials.remove(pos);
    list.updated_at = chrono_lite_now();
    save_voice_materials(&list)
}
