<script setup>
import { ref, computed, watch } from "vue";
import { storeToRefs } from "pinia";
import { useWorkflowStore } from "../../stores/workflow.js";
import {
  VOICE_CATEGORY_OPTIONS,
  filterSystemVoices,
} from "../../data/systemVoices.js";
import {
  listCloneVoices,
  deleteCloneVoice,
} from "../../services/soundPromptStorage.js";
import { previewVoice } from "../../services/voicePreview.js";
import { stripVoiceIdPrefix } from "../../utils/voiceIdPrefix.js";
import VoiceCloneEditDialog from "./VoiceCloneEditDialog.vue";

const props = defineProps({
  /** 声音页等独立场景：由父组件控制显隐与选中音色 */
  standalone: { type: Boolean, default: false },
  visible: { type: Boolean, default: false },
  selectedVoiceId: { type: String, default: "sys_Cherry" },
});

const emit = defineEmits(["update:visible", "update:selectedVoiceId", "select"]);

const workflow = useWorkflowStore();
const { voiceManageModalVisible, selectedVoiceId: workflowVoiceId } =
  storeToRefs(workflow);

const dialogVisible = computed({
  get() {
    return props.standalone ? props.visible : voiceManageModalVisible.value;
  },
  set(v) {
    if (props.standalone) {
      emit("update:visible", v);
    } else {
      voiceManageModalVisible.value = v;
    }
  },
});

const currentVoiceId = computed({
  get() {
    return props.standalone ? props.selectedVoiceId : workflowVoiceId.value;
  },
  set(v) {
    if (props.standalone) {
      emit("update:selectedVoiceId", v);
    } else {
      workflowVoiceId.value = v;
    }
  },
});

const activeTab = ref("system");
const voiceCategory = ref("putonghua");
const cloneVoices = ref([]);
const cloneLoading = ref(false);
const editDialogRef = ref(null);

const previewingKey = ref(null);
const previewPanelKey = ref(null);
const previewAudioSrc = ref("");
const previewError = ref("");
const audioRef = ref(null);

const filteredSystemVoices = computed(() =>
  filterSystemVoices(voiceCategory.value),
);

function loadCloneVoices() {
  cloneLoading.value = true;
  try {
    cloneVoices.value = listCloneVoices();
  } finally {
    cloneLoading.value = false;
  }
}

watch(dialogVisible, (open) => {
  if (open) {
    activeTab.value = "system";
    voiceCategory.value = "putonghua";
    loadCloneVoices();
  } else {
    stopPreview();
  }
});

function stopPreview() {
  previewingKey.value = null;
  previewPanelKey.value = null;
  previewAudioSrc.value = "";
  previewError.value = "";
  if (audioRef.value) {
    audioRef.value.pause();
    audioRef.value.removeAttribute("src");
  }
}

function onClose() {
  if (props.standalone) {
    dialogVisible.value = false;
  } else {
    workflow.closeVoiceManageDialog();
  }
}

function onSelectVoice(voiceId) {
  if (props.standalone) {
    currentVoiceId.value = voiceId;
    emit("select", voiceId);
    dialogVisible.value = false;
  } else {
    workflow.selectVoice(voiceId);
  }
}

function onAddClone() {
  editDialogRef.value?.openAdd();
}

function onEditClone(record) {
  editDialogRef.value?.openEdit(record);
}

function onDeleteClone(record) {
  if (!window.confirm(`确认删除音色「${record.title}」？`)) return;
  deleteCloneVoice(record.id);
  if (currentVoiceId.value === record.id) {
    if (props.standalone) {
      currentVoiceId.value = "sys_Cherry";
    } else {
      workflow.selectVoice("sys_Cherry");
    }
  }
  if (previewPanelKey.value === record.id) {
    stopPreview();
  }
  loadCloneVoices();
}

async function runPreview(opts) {
  previewError.value = "";
  previewingKey.value = opts.listKey;
  const result = await previewVoice(opts);
  previewingKey.value = null;

  if (!result.ok) {
    previewError.value = result.message;
    return;
  }

  previewPanelKey.value = opts.listKey;
  previewAudioSrc.value = result.audioSrc;
  requestAnimationFrame(() => {
    audioRef.value?.play()?.catch(() => {});
  });
}

function onPreviewSystem(voice) {
  runPreview({
    listKey: voice.id,
    title: voice.title,
    aliyunVoiceId: voice.aliyunVoiceId,
  });
}

function onPreviewClone(item) {
  const voiceId = String(item.content?.aliyunVoiceId || "").trim();
  if (!voiceId) {
    previewError.value = "请先配置音色 ID 后再试听";
    return;
  }
  runPreview({
    listKey: item.id,
    title: item.title,
    aliyunVoiceId: voiceId,
  });
}

function isPreviewing(key) {
  return previewingKey.value === key;
}

function showPreviewPlayer(key) {
  return previewPanelKey.value === key && previewAudioSrc.value;
}
</script>

<template>
  <Dialog
    v-model:visible="dialogVisible"
    modal
    header="音色管理"
    :style="{ width: '900px' }"
    :draggable="false"
    class="voice-manage-dialog"
    @hide="onClose"
  >
    <audio ref="audioRef" class="hidden" :src="previewAudioSrc || undefined" />

    <Tabs v-model:value="activeTab">
      <TabList>
        <Tab value="system">系统音色</Tab>
        <Tab value="clone">克隆音色</Tab>
      </TabList>
      <TabPanels>
        <TabPanel value="system">
          <SelectButton
            v-model="voiceCategory"
            :options="VOICE_CATEGORY_OPTIONS"
            option-label="label"
            option-value="key"
            size="small"
            class="mb-3"
          />
          <div class="voice-list-scroll max-h-[50vh] space-y-2 overflow-y-auto pr-1">
            <div
              v-for="voice in filteredSystemVoices"
              :key="voice.id"
              class="rounded-xl border border-white/10 bg-white/5 p-3 transition-colors hover:border-purple-500/40"
            >
              <div class="flex items-start justify-between gap-2">
                <div class="min-w-0 flex-1">
                  <div
                    class="inline-flex max-w-full flex-wrap items-center gap-x-2 rounded-full bg-white/5 px-2 py-1"
                  >
                    <span class="text-sm text-slate-100">{{ voice.title }}</span>
                    <span class="text-xs text-slate-500">{{ voice.desc }}</span>
                  </div>
                  <p class="mt-2 text-xs text-slate-500">音色ID: {{ voice.aliyunVoiceId }}</p>
                </div>
                <div class="flex shrink-0 gap-1">
                  <Button
                    label="试听"
                    size="small"
                    severity="secondary"
                    icon="pi pi-volume-up"
                    :loading="isPreviewing(voice.id)"
                    :disabled="Boolean(previewingKey && !isPreviewing(voice.id))"
                    @click="onPreviewSystem(voice)"
                  />
                  <Button
                    label="选择"
                    size="small"
                    icon="pi pi-check"
                    @click="onSelectVoice(voice.id)"
                  />
                </div>
              </div>
              <div
                v-if="showPreviewPlayer(voice.id)"
                class="mt-2 rounded-lg border border-blue-500/30 bg-blue-500/10 px-2 py-2"
              >
                <audio
                  :src="previewAudioSrc"
                  controls
                  class="h-8 w-full"
                  autoplay
                />
              </div>
            </div>
            <p
              v-if="filteredSystemVoices.length === 0"
              class="py-8 text-center text-sm text-slate-500"
            >
              暂无音色
            </p>
          </div>
        </TabPanel>
        <TabPanel value="clone">
          <div class="mb-3 flex justify-end">
            <Button
              label="添加克隆音色"
              size="small"
              icon="pi pi-plus"
              @click="onAddClone"
            />
          </div>
          <div class="voice-list-scroll max-h-[50vh] space-y-2 overflow-y-auto pr-1">
            <p v-if="cloneLoading" class="py-6 text-center text-sm text-slate-500">加载中...</p>
            <p
              v-else-if="cloneVoices.length === 0"
              class="py-8 text-center text-sm text-slate-500"
            >
              暂无克隆音色，点击右上角添加
            </p>
            <div
              v-for="item in cloneVoices"
              :key="item.id"
              class="rounded-xl border border-white/10 bg-white/5 p-3 transition-colors hover:border-purple-500/40"
            >
              <div class="flex items-start justify-between gap-2">
                <div class="min-w-0 flex-1">
                  <div class="truncate text-sm font-medium text-slate-100">
                    {{ item.title }}
                  </div>
                  <p v-if="item.content?.promptText" class="mt-1 text-xs text-slate-500">
                    {{ item.content.promptText }}
                  </p>
                  <p
                    v-if="item.content?.aliyunVoiceId"
                    class="mt-1 text-xs text-blue-400"
                  >
                    音色ID: {{ stripVoiceIdPrefix(item.content.aliyunVoiceId) }}
                  </p>
                  <p v-else class="mt-1 text-xs text-amber-500/90">
                    未配置音色ID（将使用默认音色）
                  </p>
                </div>
                <div class="flex shrink-0 gap-1">
                  <Button
                    label="试听"
                    size="small"
                    severity="secondary"
                    icon="pi pi-volume-up"
                    :loading="isPreviewing(item.id)"
                    :disabled="
                      !item.content?.aliyunVoiceId ||
                      Boolean(previewingKey && !isPreviewing(item.id))
                    "
                    @click="onPreviewClone(item)"
                  />
                  <Button label="选择" size="small" @click="onSelectVoice(item.id)" />
                  <Button
                    icon="pi pi-pencil"
                    size="small"
                    severity="secondary"
                    aria-label="编辑"
                    @click="onEditClone(item)"
                  />
                  <Button
                    icon="pi pi-trash"
                    size="small"
                    severity="danger"
                    aria-label="删除"
                    @click="onDeleteClone(item)"
                  />
                </div>
                </div>
              <div
                v-if="showPreviewPlayer(item.id)"
                class="mt-2 rounded-lg border border-blue-500/30 bg-blue-500/10 px-2 py-2"
              >
                <audio :src="previewAudioSrc" controls class="h-8 w-full" autoplay />
              </div>
            </div>
          </div>
        </TabPanel>
      </TabPanels>
    </Tabs>

    <p v-if="previewError" class="mt-2 text-sm text-red-400">{{ previewError }}</p>

    <VoiceCloneEditDialog ref="editDialogRef" @saved="loadCloneVoices" />
  </Dialog>
</template>
