<script setup>
import { ref, computed, onUnmounted } from "vue";
import { useRouter } from "vue-router";
import { DOUBAO_APP_ID, DOUBAO_ACCESS_TOKEN, DOUBAO_RESOURCE_ID, DOUBAO_TTS_API_PATH, DOUBAO_AUDIO_FORMAT, DOUBAO_SAMPLE_RATE } from "@/config/index.js";

const router = useRouter();
const textInput = ref("");
const selectedVoice = ref("1");
const activeCategory = ref("all");
const isGenerating = ref(false);

// 示例语句列表
const exampleSentences = [
  "Hello, how are you today?",
  "The weather is beautiful today.",
  "Practice makes perfect.",
  "Where there is a will, there is a way.",
  "Knowledge is power.",
];

// 添加示例语句到文本框
const addExampleSentence = () => {
  const randomIndex = Math.floor(Math.random() * exampleSentences.length);
  textInput.value = exampleSentences[randomIndex];
};

// 兼容不支持 crypto.randomUUID 的浏览器
const generateUUID = () => {
  if (typeof crypto.randomUUID === 'function') {
    return crypto.randomUUID();
  }
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
};

// 真实音频播放相关状态
const audioUrl = ref(null);
const isPlaying = ref(false);
const progress = ref(0);
const currentTime = ref("00:00");
const durationTime = ref("00:00");
let audioInstance = null;

// 模拟正在播放的试听音频ID
const playingDemoId = ref(null);
let demoAudioInstance = null; // 试听专用音频实例

const categories = [
  { id: "all", name: "全部音色" },
  { id: "female", name: "女声" },
  { id: "male", name: "男声" },
];

// 音色列表（来源：豆包 TTS 音色库）
const voices = ref([
  // ===== 英语音色 =====
  {
    id: "1",
    name: "Dacey (美音)",
    category: "female",
    tags: ["女声", "美音", "清晰"],
    avatar: "👩🏼",
    voice_type: "en_female_dacey_uranus_bigtts",
    demo_text:
      "Hello! Welcome to our English pronunciation practice. I hope you enjoy learning with me.",
  },
  {
    id: "2",
    name: "Tim (美音)",
    category: "male",
    tags: ["男声", "美音", "磁性"],
    avatar: "👨🏼",
    voice_type: "en_male_tim_uranus_bigtts",
    demo_text:
      "Good morning! Today is a beautiful day to learn English. Let us practice together.",
  },
  {
    id: "3",
    name: "Stokie (美音)",
    category: "female",
    tags: ["女声", "美音", "活泼"],
    avatar: "👩🏻",
    voice_type: "en_female_stokie_uranus_bigtts",
    demo_text:
      "Hi there! I am so excited to help you improve your English pronunciation today!",
  },
  {
    id: "4",
    name: "Tina 老师 (英音)",
    category: "female",
    tags: ["女声", "英音", "专业"],
    avatar: "👩‍🏫",
    voice_type: "zh_female_yingyujiaoxue_uranus_bigtts",
    demo_text:
      "Welcome to English class. I will help you master British English pronunciation step by step.",
  },

  // ===== 中文女声 =====
  {
    id: "5",
    name: "Vivi 2.0",
    category: "female",
    tags: ["女声", "多语种", "情感"],
    avatar: "👩🏻",
    voice_type: "zh_female_vv_uranus_bigtts",
    demo_text: "你好，很高兴认识你。今天天气真好，让我们一起愉快地交流吧。",
  },
  {
    id: "6",
    name: "小何 2.0",
    category: "female",
    tags: ["女声", "温柔", "情感"],
    avatar: "👩🏻",
    voice_type: "zh_female_xiaohe_uranus_bigtts",
    demo_text: "大家好，我是小何。希望能用我的声音温暖你的每一天。",
  },
  {
    id: "7",
    name: "清新女声 2.0",
    category: "female",
    tags: ["女声", "清新", "自然"],
    avatar: "🌸",
    voice_type: "zh_female_qingxinnvsheng_uranus_bigtts",
    demo_text: "清晨的阳光洒在窗前，新的一天开始了，愿你心情愉快。",
  },
  {
    id: "8",
    name: "甜美小源 2.0",
    category: "female",
    tags: ["女声", "甜美", "可爱"],
    avatar: "🍬",
    voice_type: "zh_female_tianmeixiaoyuan_uranus_bigtts",
    demo_text: "嗨，我是小源，很高兴能和你聊天，今天有什么有趣的事吗？",
  },
  {
    id: "9",
    name: "甜美桃子 2.0",
    category: "female",
    tags: ["女声", "甜美", "活泼"],
    avatar: "🍑",
    voice_type: "zh_female_tianmeitaozi_uranus_bigtts",
    demo_text: "大家好呀，我是桃子，希望能给你带来快乐和甜蜜。",
  },
  {
    id: "10",
    name: "爽快思思 2.0",
    category: "female",
    tags: ["女声", "爽朗", "干练"],
    avatar: "💪",
    voice_type: "zh_female_shuangkuaisisi_uranus_bigtts",
    demo_text: "没问题，交给我吧！我一定会把事情办得漂漂亮亮的。",
  },
  {
    id: "11",
    name: "邻家女孩 2.0",
    category: "female",
    tags: ["女声", "亲切", "邻家"],
    avatar: "👧",
    voice_type: "zh_female_linjianvhai_uranus_bigtts",
    demo_text: "嗨，好久不见啦！最近过得怎么样呀？",
  },
  {
    id: "12",
    name: "魅力女友 2.0",
    category: "female",
    tags: ["女声", "魅力", "温柔"],
    avatar: "💕",
    voice_type: "zh_female_meilinvyou_uranus_bigtts",
    demo_text: "亲爱的，今天想我了吗？我会一直陪在你身边的。",
  },
  {
    id: "13",
    name: "流畅女声 2.0",
    category: "female",
    tags: ["女声", "流畅", "专业"],
    avatar: "🎙️",
    voice_type: "zh_female_liuchangnv_uranus_bigtts",
    demo_text: "欢迎收听本期节目，今天我们要聊的话题非常精彩，一起来听听吧。",
  },
  {
    id: "14",
    name: "鸡汤女 2.0",
    category: "female",
    tags: ["女声", "励志", "温暖"],
    avatar: "📖",
    voice_type: "zh_female_jitangnv_uranus_bigtts",
    demo_text: "每一天都是新的开始，相信自己，你一定可以创造奇迹。",
  },
  {
    id: "15",
    name: "黑猫咪仔 2.0",
    category: "female",
    tags: ["女声", "故事", "神秘"],
    avatar: "🐱",
    voice_type: "zh_female_mizai_uranus_bigtts",
    demo_text: "喵～侦探社的故事又要开始了，这次会有什么神秘案件呢？",
  },

  // ===== 中文男声 =====
  {
    id: "16",
    name: "云舟 2.0",
    category: "male",
    tags: ["男声", "沉稳", "大气"],
    avatar: "👨🏻",
    voice_type: "zh_male_m191_uranus_bigtts",
    demo_text: "大家好，欢迎来到这里。希望今天的内容能对你有所帮助。",
  },
  {
    id: "17",
    name: "小天 2.0",
    category: "male",
    tags: ["男声", "阳光", "活力"],
    avatar: "🌞",
    voice_type: "zh_male_taocheng_uranus_bigtts",
    demo_text: "嘿，我是小天！今天又是元气满满的一天，一起加油吧！",
  },
  {
    id: "18",
    name: "刘飞 2.0",
    category: "male",
    tags: ["男声", "磁性", "成熟"],
    avatar: "🎤",
    voice_type: "zh_male_liufei_uranus_bigtts",
    demo_text: "很高兴能在这里与你相遇，希望我的声音能给你带来好心情。",
  },
  {
    id: "19",
    name: "魅力苏菲 2.0",
    category: "male",
    tags: ["男声", "魅力", "低沉"],
    avatar: "🎭",
    voice_type: "zh_male_sophie_uranus_bigtts",
    demo_text: "夜深了，让我为你讲一个故事，愿你有个好梦。",
  },
  {
    id: "20",
    name: "少年梓辛 2.0",
    category: "male",
    tags: ["男声", "少年", "青春"],
    avatar: "👦",
    voice_type: "zh_male_shaonianzixin_uranus_bigtts",
    demo_text: "大家好，我是梓辛，很高兴认识你们，以后请多多关照！",
  },
  {
    id: "21",
    name: "猴哥 2.0",
    category: "male",
    tags: ["男声", "角色", "特色"],
    avatar: "🐵",
    voice_type: "zh_male_sunwukong_uranus_bigtts",
    demo_text: "嘿嘿，俺老孙来也！有什么能帮到你的，尽管说！",
  },
  {
    id: "22",
    name: "大壹 2.0",
    category: "male",
    tags: ["男声", "配音", "专业"],
    avatar: "🎬",
    voice_type: "zh_male_dayi_uranus_bigtts",
    demo_text: "欢迎观看本期视频，今天我们来讲一个有趣的话题。",
  },
  {
    id: "23",
    name: "儒雅逸辰 2.0",
    category: "male",
    tags: ["男声", "儒雅", "书卷"],
    avatar: "📚",
    voice_type: "zh_male_ruyayichen_uranus_bigtts",
    demo_text: "古人云，学而时习之，不亦说乎。让我们一起探索知识的海洋。",
  },

  // ===== 角色扮演 =====
  {
    id: "24",
    name: "知性灿灿 2.0",
    category: "female",
    tags: ["女声", "知性", "优雅"],
    avatar: "👩‍💼",
    voice_type: "zh_female_cancan_uranus_bigtts",
    demo_text: "你好，很高兴为你服务。有什么问题都可以来问我哦。",
  },
  {
    id: "25",
    name: "撒娇学妹 2.0",
    category: "female",
    tags: ["女声", "撒娇", "可爱"],
    avatar: "🎀",
    voice_type: "zh_female_sajiaoxuemei_uranus_bigtts",
    demo_text: "学长～人家今天好想你呀，你有没有想人家嘛～",
  },
  {
    id: "26",
    name: "可爱女生",
    category: "female",
    tags: ["女声", "可爱", "萌系"],
    avatar: "💖",
    voice_type: "saturn_zh_female_keainvsheng_tob",
    demo_text: "哇，你好呀！今天的你看起来好棒哦，要继续保持呢！",
  },
  {
    id: "27",
    name: "调皮公主",
    category: "female",
    tags: ["女声", "调皮", "俏皮"],
    avatar: "👸",
    voice_type: "saturn_zh_female_tiaopigongzhu_tob",
    demo_text: "哼，本公主今天心情好，就陪你聊聊天吧～",
  },
  {
    id: "28",
    name: "爽朗少年",
    category: "male",
    tags: ["男声", "爽朗", "少年"],
    avatar: "😄",
    voice_type: "saturn_zh_male_shuanglangshaonian_tob",
    demo_text: "嘿，哥们儿！今天打球去不？保证让你玩得痛快！",
  },
  {
    id: "29",
    name: "天才同桌",
    category: "male",
    tags: ["男声", "学霸", "少年"],
    avatar: "🤓",
    voice_type: "saturn_zh_male_tiancaitongzhuo_tob",
    demo_text: "这道题很简单啊，你看，只要这样算就能得出答案了。",
  },
  {
    id: "30",
    name: "知性灿灿",
    category: "female",
    tags: ["女声", "知性", "温柔"],
    avatar: "💼",
    voice_type: "saturn_zh_female_cancan_tob",
    demo_text: "让我们一起分析这个问题吧，相信很快就能找到解决办法。",
  },

  // ===== 儿童音 =====
  {
    id: "31",
    name: "儿童绘本 2.0",
    category: "female",
    tags: ["女声", "儿童", "故事"],
    avatar: "📚",
    voice_type: "zh_female_xiaoxue_uranus_bigtts",
    demo_text: "小朋友们好呀，今天要给你们讲一个好听的故事，准备好了吗？",
  },
  {
    id: "32",
    name: "佩奇猪 2.0",
    category: "female",
    tags: ["女声", "儿童", "角色"],
    avatar: "🐷",
    voice_type: "zh_female_peiqi_uranus_bigtts",
    demo_text: "大家好，我是佩奇，今天我要和弟弟乔治一起去公园玩啦！",
  },

  // ===== 客服音 =====
  {
    id: "33",
    name: "暖阳女声 2.0",
    category: "female",
    tags: ["女声", "客服", "温暖"],
    avatar: "☀️",
    voice_type: "zh_female_kefunvsheng_uranus_bigtts",
    demo_text: "您好，很高兴为您服务，请问有什么可以帮助您的吗？",
  },
  {
    id: "34",
    name: "轻盈朵朵 2.0",
    category: "female",
    tags: ["女声", "客服", "轻盈"],
    avatar: "🌼",
    voice_type: "saturn_zh_female_qingyingduoduo_cs_tob",
    demo_text: "您好，欢迎咨询，我会尽力为您解答所有问题的。",
  },
  {
    id: "35",
    name: "温婉珊珊 2.0",
    category: "female",
    tags: ["女声", "客服", "温婉"],
    avatar: "🌷",
    voice_type: "saturn_zh_female_wenwanshanshan_cs_tob",
    demo_text: "感谢您的来电，请问有什么需要帮助的地方呢？",
  },
  {
    id: "36",
    name: "热情艾娜 2.0",
    category: "female",
    tags: ["女声", "客服", "热情"],
    avatar: "🔥",
    voice_type: "saturn_zh_female_reqingaina_cs_tob",
    demo_text: "您好您好！非常高兴为您服务，有什么问题尽管问我哦！",
  },
]);

const filteredVoices = computed(() => {
  if (activeCategory.value === "all") return voices.value;
  return voices.value.filter((v) => v.category === activeCategory.value);
});

const handleDemoPlay = async (id) => {
  // 如果正在播放同一个，则停止
  if (playingDemoId.value === id) {
    if (demoAudioInstance) {
      demoAudioInstance.pause();
      demoAudioInstance = null;
    }
    playingDemoId.value = null;
    return;
  }

  // 停止之前的试听
  if (demoAudioInstance) {
    demoAudioInstance.pause();
    demoAudioInstance = null;
  }

  // 标记开始播放
  playingDemoId.value = id;

  const voice = voices.value.find((v) => v.id === id);
  if (!voice || !voice.demo_text) {
    playingDemoId.value = null;
    return;
  }

  try {
    // 调用 TTS API 生成试听音频
    const payload = {
      user: { uid: "demo_" + Date.now() },
      req_params: {
        text: voice.demo_text,
        speaker: voice.voice_type,
        audio_params: { format: DOUBAO_AUDIO_FORMAT, sample_rate: DOUBAO_SAMPLE_RATE },
      },
    };

    const response = await fetch(DOUBAO_TTS_API_PATH, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Api-App-Id": DOUBAO_APP_ID,
        "X-Api-Access-Key": DOUBAO_ACCESS_TOKEN,
        "X-Api-Resource-Id": DOUBAO_RESOURCE_ID,
        "X-Api-Request-Id": generateUUID(),
      },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    // 读取流式响应
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = "";
    let audioChunks = [];

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      buffer += decoder.decode(value, { stream: true });

      const lines = buffer.split("\n");
      buffer = lines.pop();

      for (const line of lines) {
        if (!line.trim()) continue;
        try {
          const resData = JSON.parse(line);
          if (resData.code === 0 && resData.data) {
            const binaryString = window.atob(resData.data);
            const bytes = new Uint8Array(binaryString.length);
            for (let i = 0; i < binaryString.length; i++) {
              bytes[i] = binaryString.charCodeAt(i);
            }
            audioChunks.push(bytes);
          }
        } catch (e) {}
      }
    }

    // 处理剩余缓冲区
    if (buffer.trim()) {
      try {
        const resData = JSON.parse(buffer);
        if (resData.code === 0 && resData.data) {
          const binaryString = window.atob(resData.data);
          const bytes = new Uint8Array(binaryString.length);
          for (let i = 0; i < binaryString.length; i++) {
            bytes[i] = binaryString.charCodeAt(i);
          }
          audioChunks.push(bytes);
        }
      } catch (e) {}
    }

    // 播放音频
    if (audioChunks.length > 0) {
      const totalLength = audioChunks.reduce((acc, val) => acc + val.length, 0);
      const allBytes = new Uint8Array(totalLength);
      let offset = 0;
      for (const chunk of audioChunks) {
        allBytes.set(chunk, offset);
        offset += chunk.length;
      }

      const blob = new Blob([allBytes], { type: "audio/mp3" });
      const url = URL.createObjectURL(blob);

      demoAudioInstance = new Audio(url);
      demoAudioInstance.onended = () => {
        playingDemoId.value = null;
        URL.revokeObjectURL(url);
      };
      demoAudioInstance.onerror = () => {
        playingDemoId.value = null;
      };
      demoAudioInstance.play();
    } else {
      playingDemoId.value = null;
    }
  } catch (error) {
    console.error("Demo play error:", error);
    playingDemoId.value = null;
  }
};

// 格式化时间显示
const formatTime = (seconds) => {
  if (!seconds || isNaN(seconds)) return "00:00";
  const m = Math.floor(seconds / 60)
    .toString()
    .padStart(2, "0");
  const s = Math.floor(seconds % 60)
    .toString()
    .padStart(2, "0");
  return `${m}:${s}`;
};

// 初始化真实的音频播放器
const initAudio = (src) => {
  if (audioInstance) {
    audioInstance.pause();
  }
  audioInstance = new Audio(src);

  audioInstance.addEventListener("timeupdate", () => {
    const curr = audioInstance.currentTime;
    const dur = audioInstance.duration || 0;
    if (dur > 0) {
      progress.value = (curr / dur) * 100;
    }
    currentTime.value = formatTime(curr);
  });

  audioInstance.addEventListener("loadedmetadata", () => {
    durationTime.value = formatTime(audioInstance.duration);
  });

  audioInstance.addEventListener("ended", () => {
    isPlaying.value = false;
    progress.value = 0;
    currentTime.value = "00:00";
  });
};

// 播放/暂停控制
const togglePlay = () => {
  if (!audioInstance) return;
  if (isPlaying.value) {
    audioInstance.pause();
  } else {
    audioInstance.play();
  }
  isPlaying.value = !isPlaying.value;
};

// 真正的豆包 API 调用逻辑 (升级为V3 HTTP Chunked协议)
const handleGenerate = async () => {
  if (!textInput.value.trim()) return;

  // 校验参数是否填写
  if (
    DOUBAO_APP_ID === "YOUR_APP_ID" ||
    DOUBAO_ACCESS_TOKEN === "YOUR_ACCESS_TOKEN"
  ) {
    alert(
      "请先在代码顶部配置 DOUBAO_APP_ID 和 DOUBAO_ACCESS_TOKEN 才能调用真实的 AI 发音！"
    );
    return;
  }

  isGenerating.value = true;
  audioUrl.value = null;
  if (audioInstance) {
    audioInstance.pause();
    isPlaying.value = false;
  }

  try {
    const selectedVoiceData = voices.value.find(
      (v) => v.id === selectedVoice.value
    );

    // 构造 V3 API 请求体
    const payload = {
      user: {
        uid: "user_" + Date.now(),
      },
      req_params: {
        text: textInput.value,
        speaker: selectedVoiceData.voice_type,
        audio_params: {
          format: DOUBAO_AUDIO_FORMAT,
          sample_rate: DOUBAO_SAMPLE_RATE,
        },
      },
    };

    // 调用配置的代理路径避免跨域 (指向 https://openspeech.bytedance.com/api/v3/tts/unidirectional)
    const response = await fetch(DOUBAO_TTS_API_PATH, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Api-App-Id": DOUBAO_APP_ID,
        "X-Api-Access-Key": DOUBAO_ACCESS_TOKEN,
        "X-Api-Resource-Id": DOUBAO_RESOURCE_ID,
        "X-Api-Request-Id": generateUUID(),
      },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      const err = await response.text();
      throw new Error(`HTTP ${response.status}: ${err}`);
    }

    // 读取流式响应 (Chunked JSON)
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = "";
    let audioChunks = []; // 收集二进制数据

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      buffer += decoder.decode(value, { stream: true });

      // V3 的 HTTP Chunked 数据通常每段是一个独立的 JSON，可能有换行符分隔
      // 但也可能是一次性传输，我们按照逐行或独立JSON块尝试解析
      const lines = buffer.split("\n");
      buffer = lines.pop(); // 最后一行可能不完整，保留到下一次

      for (const line of lines) {
        if (!line.trim()) continue;
        try {
          const resData = JSON.parse(line);

          if (resData.code === 3001) {
            throw new Error(
              "API报错 3001: 权限不足。您当前使用的 AppID 未配置或未授权该音色。"
            );
          }

          // 20000000 表示合成成功结束
          if (resData.code === 20000000) {
            break;
          }

          // 获取音频流
          if (resData.code === 0 && resData.data) {
            // 解析Base64音频块并拼接到数组
            const binaryString = window.atob(resData.data);
            const len = binaryString.length;
            const bytes = new Uint8Array(len);
            for (let i = 0; i < len; i++) {
              bytes[i] = binaryString.charCodeAt(i);
            }
            audioChunks.push(bytes);
          } else if (resData.code > 0) {
            throw new Error(
              `[${resData.code}] ${resData.message || "未知错误"}`
            );
          }
        } catch (e) {
          // 如果是我们的抛出的特定业务错误，直接往外层抛出
          if (e.message.startsWith("API报错") || e.message.startsWith("["))
            throw e;
          // 否则可能是由于被不小心截断的 JSON（虽然按行分割大概率安全，但若无换行则忽略继续收集）
        }
      }
    }

    // 检查缓冲区中剩余内容
    if (buffer.trim()) {
      try {
        const resData = JSON.parse(buffer);
        if (resData.code === 3001)
          throw new Error(
            "API报错 3001: 权限不足。您当前使用的 AppID 未配置或未授权该音色。"
          );
        if (resData.code === 0 && resData.data) {
          const binaryString = window.atob(resData.data);
          const len = binaryString.length;
          const bytes = new Uint8Array(len);
          for (let i = 0; i < len; i++) {
            bytes[i] = binaryString.charCodeAt(i);
          }
          audioChunks.push(bytes);
        } else if (resData.code > 0 && resData.code !== 20000000) {
          throw new Error(`[${resData.code}] ${resData.message || "未知错误"}`);
        }
      } catch (e) {
        if (e.message.startsWith("API报错") || e.message.startsWith("["))
          throw e;
      }
    }

    // 合并完整的音频数据为可播放格式
    if (audioChunks.length > 0) {
      const totalLength = audioChunks.reduce((acc, val) => acc + val.length, 0);
      const allBytes = new Uint8Array(totalLength);
      let offset = 0;
      for (const chunk of audioChunks) {
        allBytes.set(chunk, offset);
        offset += chunk.length;
      }

      // 转换为 Blob URL 交给播放器
      const blob = new Blob([allBytes], { type: "audio/mp3" });
      audioUrl.value = URL.createObjectURL(blob);
      initAudio(audioUrl.value);

      // 自动开始播放
      setTimeout(() => {
        togglePlay();
      }, 100);
    } else {
      alert(
        "未收到任何音频数据，请检查所选音色(Resource ID)是否已在后台开通！"
      );
    }
  } catch (error) {
    console.error("TTS API Error:", error);
    if (error.message.includes("3001")) {
      alert(
        `权限不足！\n原因: 您的 AppID 没有开通当前音色或Resource ID的使用权限。\n解决办法: 请登录火山引擎控制台->语音技术->应用管理，确认已添加该音色。`
      );
    } else {
      alert(`请求豆包 API 失败:\n${error.message}`);
    }
  } finally {
    isGenerating.value = false;
  }
};

const handleDownload = () => {
  if (!audioUrl.value) return;
  const a = document.createElement("a");
  a.href = audioUrl.value;
  a.download = "AI_Pronunciation.mp3";
  a.click();
};

onUnmounted(() => {
  if (audioInstance) {
    audioInstance.pause();
    audioInstance = null;
  }
  if (demoAudioInstance) {
    demoAudioInstance.pause();
    demoAudioInstance = null;
  }
});
</script>

<template>
  <div class="page-container">
    <nav class="nav-bar">
      <button @click="router.push('/')" class="back-btn">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
          stroke-width="2"
          stroke="currentColor"
        >
          <path
            stroke-linecap="round"
            stroke-linejoin="round"
            d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"
          />
        </svg>
        返回首页
      </button>
      <div class="nav-title">AI 英语发音</div>
    </nav>

    <div class="content-grid">
      <!-- 左侧：输入区域 -->
      <div class="panel input-panel">
        <div class="panel-header">
          <h3>输入待发音内容</h3>
          <span class="char-count">{{ textInput.length }} / 500</span>
        </div>

        <textarea
          v-model="textInput"
          class="text-area"
          placeholder="请输入需要朗读的英语单词或长难句..."
          maxlength="500"
        ></textarea>

        <div class="example-area">
          <button class="example-btn" @click="addExampleSentence">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              stroke-width="2"
              stroke="currentColor"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456ZM16.5 19.5 16 21l-.5-1.5-1.5-.5L15 21l.5 1.5 1.5.5Z"
              />
            </svg>
            添加示例语句
          </button>
        </div>

        <div class="action-area">
          <button
            class="primary-btn"
            :disabled="!textInput.trim() || isGenerating"
            @click="handleGenerate"
          >
            <svg
              v-if="!isGenerating"
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              stroke-width="2"
              stroke="currentColor"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z"
              />
            </svg>
            <svg
              v-else
              class="spinner"
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
            >
              <circle
                class="opacity-25"
                cx="12"
                cy="12"
                r="10"
                stroke="currentColor"
                stroke-width="4"
              ></circle>
              <path
                class="opacity-75"
                fill="currentColor"
                d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
              ></path>
            </svg>
            {{ isGenerating ? "AI 合成中..." : "开始合成发音" }}
          </button>
        </div>

        <!-- 生成结果展示区域 -->
        <div v-if="audioUrl" class="result-area">
          <div class="result-header">
            <h4>合成结果</h4>
            <button class="download-btn" @click="handleDownload">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                stroke-width="1.5"
                stroke="currentColor"
              >
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"
                />
              </svg>
              保存音频
            </button>
          </div>
          <div class="audio-player-mock">
            <div class="play-control" @click="togglePlay">
              <!-- Pause Icon -->
              <svg
                v-if="isPlaying"
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                stroke-width="1.5"
                stroke="currentColor"
              >
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  d="M15.75 5.25v13.5m-7.5-13.5v13.5"
                />
              </svg>
              <!-- Play Icon -->
              <svg
                v-else
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                stroke-width="1.5"
                stroke="currentColor"
              >
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z"
                />
              </svg>
            </div>
            <div class="progress-bar">
              <div
                class="progress-fill"
                :style="{ width: progress + '%' }"
              ></div>
            </div>
            <span class="time">{{ currentTime }} / {{ durationTime }}</span>
          </div>
        </div>
      </div>

      <!-- 右侧：发音人选择区域 -->
      <div class="panel voice-panel">
        <div class="panel-header">
          <h3>选择 AI 发音人</h3>
        </div>

        <div class="category-tabs">
          <button
            v-for="cat in categories"
            :key="cat.id"
            class="tab-btn"
            :class="{ active: activeCategory === cat.id }"
            @click="activeCategory = cat.id"
          >
            {{ cat.name }}
          </button>
        </div>

        <div class="voices-list">
          <div
            v-for="voice in filteredVoices"
            :key="voice.id"
            class="voice-card"
            :class="{ selected: selectedVoice === voice.id }"
            @click="selectedVoice = voice.id"
          >
            <div class="voice-avatar">{{ voice.avatar }}</div>
            <div class="voice-info">
              <div class="voice-name">{{ voice.name }}</div>
              <div class="voice-tags">
                <span v-for="tag in voice.tags" :key="tag" class="tag">{{
                  tag
                }}</span>
              </div>
            </div>

            <button
              class="demo-btn"
              :class="{ playing: playingDemoId === voice.id }"
              @click.stop="handleDemoPlay(voice.id)"
              title="试听音色"
            >
              <svg
                v-if="playingDemoId !== voice.id"
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                stroke-width="2"
                stroke="currentColor"
              >
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z"
                />
              </svg>
              <div v-else class="playing-bars">
                <span></span><span></span><span></span>
              </div>
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
* {
  box-sizing: border-box;
}
.page-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.nav-bar {
  display: flex;
  align-items: center;
  margin-bottom: 2rem;
}

.back-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: 1rem;
  cursor: pointer;
  padding: 0.5rem 1rem;
  border-radius: 8px;
  transition: all 0.2s;
}

.back-btn:hover {
  background: var(--card-bg);
  color: var(--text-primary);
}

.back-btn svg {
  width: 20px;
  height: 20px;
}

.nav-title {
  font-size: 1.5rem;
  font-weight: 600;
  margin-left: auto;
  margin-right: auto;
  transform: translateX(-40px); /* offset the back button width */
}

.content-grid {
  display: grid;
  grid-template-columns: 1fr 400px;
  gap: 2rem;
  flex: 1;
  min-height: 0;
}

.panel {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 20px;
  backdrop-filter: blur(12px);
  padding: 2rem;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
}

.panel-header h3 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
}

.char-count {
  color: var(--text-secondary);
  font-size: 0.875rem;
}

/* Input Area */
.text-area {
  flex: 1;
  width: 100%;
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 1.5rem;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 1.1rem;
  line-height: 1.6;
  resize: none;
  outline: none;
  box-sizing: border-box;
  transition: border-color 0.3s;
  min-height: 200px;
}

.text-area:focus {
  border-color: var(--accent-1);
}

.example-area {
  margin-top: 1rem;
  display: flex;
  gap: 0.5rem;
}

.example-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--card-border);
  color: var(--text-secondary);
  padding: 0.5rem 1rem;
  border-radius: 8px;
  cursor: pointer;
  font-size: 0.875rem;
  transition: all 0.2s;
}

.example-btn:hover {
  background: rgba(255, 255, 255, 0.1);
  color: var(--text-primary);
  border-color: var(--accent-1);
}

.example-btn svg {
  width: 16px;
  height: 16px;
}

.action-area {
  margin-top: 1.5rem;
  display: flex;
  justify-content: flex-end;
}

.primary-btn {
  background: linear-gradient(135deg, var(--accent-1), #4f46e5);
  color: white;
  border: none;
  padding: 1rem 2rem;
  border-radius: 12px;
  font-size: 1.1rem;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  transition: all 0.3s;
  box-shadow: 0 4px 15px rgba(99, 102, 241, 0.3);
}

.primary-btn:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(99, 102, 241, 0.4);
}

.primary-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
}

.primary-btn svg {
  width: 24px;
  height: 24px;
}

/* Spinner */
.spinner {
  animation: spin 1s linear infinite;
}
@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
.opacity-25 {
  opacity: 0.25;
}
.opacity-75 {
  opacity: 0.75;
}

/* Voice Selection */
.category-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
  overflow-x: auto;
  padding-bottom: 0.5rem;
}

.tab-btn {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid transparent;
  color: var(--text-secondary);
  padding: 0.5rem 1rem;
  border-radius: 20px;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.2s;
}

.tab-btn:hover {
  background: rgba(255, 255, 255, 0.1);
}

.tab-btn.active {
  background: var(--accent-bg, rgba(99, 102, 241, 0.15));
  color: var(--accent-1);
  border-color: rgba(99, 102, 241, 0.3);
}

.voices-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  padding-right: 0.5rem;
}

.voices-list::-webkit-scrollbar {
  width: 6px;
}
.voices-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 3px;
}

.voice-card {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.2s;
}

.voice-card:hover {
  background: rgba(255, 255, 255, 0.05);
}

.voice-card.selected {
  border-color: var(--accent-1);
  background: linear-gradient(
    to right,
    rgba(99, 102, 241, 0.1),
    rgba(0, 0, 0, 0.2)
  );
}

.voice-avatar {
  font-size: 2rem;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 50%;
}

.voice-info {
  flex: 1;
}

.voice-name {
  font-weight: 600;
  margin-bottom: 0.25rem;
}

.voice-tags {
  display: flex;
  gap: 0.5rem;
}

.tag {
  font-size: 0.75rem;
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.05);
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
}

.demo-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  border: none;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
}

.demo-btn:hover {
  background: var(--accent-1);
  transform: scale(1.1);
}

.demo-btn.playing {
  background: var(--accent-1);
}

.demo-btn svg {
  width: 18px;
  height: 18px;
}

/* Playing Animation */
.playing-bars {
  display: flex;
  gap: 2px;
  height: 14px;
  align-items: flex-end;
}
.playing-bars span {
  width: 3px;
  background: white;
  border-radius: 2px;
  animation: bounce 0.5s infinite alternate;
}
.playing-bars span:nth-child(2) {
  animation-delay: 0.2s;
}
.playing-bars span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes bounce {
  from {
    height: 4px;
  }
  to {
    height: 14px;
  }
}

/* Result Area */
.result-area {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--card-border);
  animation: slideUp 0.3s ease-out;
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.result-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.result-header h4 {
  margin: 0;
  color: var(--accent-4);
}

.download-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: rgba(20, 184, 166, 0.1);
  color: #2dd4bf;
  border: 1px solid rgba(20, 184, 166, 0.3);
  padding: 0.5rem 1rem;
  border-radius: 8px;
  cursor: pointer;
  font-size: 0.875rem;
  transition: all 0.2s;
}

.download-btn:hover {
  background: rgba(20, 184, 166, 0.2);
}

.download-btn svg {
  width: 16px;
  height: 16px;
}

.audio-player-mock {
  display: flex;
  align-items: center;
  gap: 1rem;
  background: rgba(0, 0, 0, 0.2);
  padding: 1rem;
  border-radius: 12px;
}

.play-control {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--accent-4);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.play-control svg {
  width: 20px;
  height: 20px;
}

.progress-bar {
  flex: 1;
  height: 6px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 3px;
  overflow: hidden;
}

.progress-fill {
  width: 0%;
  height: 100%;
  background: var(--accent-4);
}

.time {
  font-size: 0.875rem;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 900px) {
  .content-grid {
    grid-template-columns: 1fr;
  }
  .page-container {
    height: auto;
  }
}
</style>
