<script setup lang="ts">
import { ref, reactive, computed, watch, onUnmounted } from "vue";
import { Modal } from "ant-design-vue";
import { SoundTwoTone, SoundOutlined, TranslationOutlined, AudioOutlined } from "@ant-design/icons-vue";
import { useI18n } from "vue-i18n";
import axios from "axios";
import { useSettingsStore } from "@/stores/config.ts";
import { setUiLocale, UiLocale } from "@/i18n";

const props = defineProps({
    open: { type: Boolean, default: false },
});
const emit = defineEmits(["update:open"]);

const { t } = useI18n();
const base_url = axios.defaults.baseURL;
const settingsStore = useSettingsStore();

const activeTab = ref<string>("main");
const loading = ref<boolean>(false);
const appVersion = "1.2.0";

// ---- 各项设置的本地状态（打开时从 store / 后端同步）----
const uiLanguage = ref<UiLocale>((settingsStore.$state.uiLanguage as UiLocale) ?? "en");
const recognitionLanguage = ref<string>(settingsStore.$state.language || "zh");
const echoCancel = ref<boolean>(settingsStore.$state.echoCancel ?? true);
const inputDeviceIndex = ref<number | null>(settingsStore.$state.inputDeviceIndex ?? null);
const outputDeviceIndex = ref<number | null>(settingsStore.$state.outputDeviceIndex ?? null);
const role = ref<string>(settingsStore.$state.role || "");

const languages = reactive<string[]>([]);
const inputDevices = reactive<any[]>([]);
const outputDevices = reactive<any[]>([]);
const roles = reactive<any[]>([]);

// ---- Prompt ----
const promptLang = ref<string>("zh");
const default_prompt_en = ref<string>("");
const default_prompt_zh = ref<string>("");
const current_prompt_en = ref<string>("");
const current_prompt_zh = ref<string>("");

const filteredRoles = computed(() => {
    const is_chinese = recognitionLanguage.value === "zh";
    return roles.filter((r) => r["is_chinese_voice"] === is_chinese);
});

// 切换识别语言后，自动选中第一个匹配音色
watch(
    () => recognitionLanguage.value,
    () => {
        if (filteredRoles.value.length > 0) {
            const exists = filteredRoles.value.find((r) => r["id"] === role.value);
            role.value = exists ? role.value : filteredRoles.value[0]["id"];
        } else {
            role.value = "";
        }
    }
);

// 界面语言即时生效（让用户立刻看到切换效果）
watch(uiLanguage, (v) => setUiLocale(v));

// ---- 数据加载 ----
const fetchASRLanguages = async () => {
    try {
        const res = await fetch(`${base_url}/asr/languages`);
        const data = await res.json();
        if (data?.languages) {
            languages.splice(0, languages.length, ...data.languages);
            // 优先沿用本地已保存/默认的识别语言（默认中文），不被后端当前值覆盖
            const saved = settingsStore.$state.language;
            recognitionLanguage.value = saved && data.languages.includes(saved)
                ? saved
                : (data.languages.includes('zh') ? 'zh' : data.languages[0]);
        }
    } catch (e) {
        console.error("Error fetching ASR languages:", e);
    }
};

const fetchTTSRoles = async () => {
    try {
        const res = await fetch(`${base_url}/tts/models`);
        const data = await res.json();
        if (data?.models) {
            roles.splice(0, roles.length, ...data.models);
            if (data.current_model_id) role.value = data.current_model_id;
        }
    } catch (e) {
        console.error("Error fetching TTS roles:", e);
    }
};

const fetchInputDevices = async () => {
    try {
        const res = await fetch(`${base_url}/system/audio-devices`);
        const data = await res.json();
        if (data?.devices) {
            inputDevices.splice(0, inputDevices.length, ...data.devices);
            const saved = settingsStore.$state.inputDeviceIndex;
            const exists = saved != null && data.devices.some((d: any) => d.index === saved);
            inputDeviceIndex.value = exists ? saved : (data.current_device_index ?? null);
        }
        if (data?.output_devices) {
            outputDevices.splice(0, outputDevices.length, ...data.output_devices);
            const saved = settingsStore.$state.outputDeviceIndex;
            const exists = saved != null && data.output_devices.some((d: any) => d.index === saved);
            outputDeviceIndex.value = exists ? saved : (data.current_output_device_index ?? null);
        }
    } catch (e) {
        console.error("Error fetching input devices:", e);
    }
};

// 当前实际生效的 ASR 引擎（由后端返回，区分 Qwen / FunASR+Whisper 等）
const asrEngineName = ref<string>("");
const asrEngineKeys = ref<string[]>([]);
const ASR_ENGINE_LINKS: Record<string, { name: string; url: string }> = {
    qwen: { name: "Qwen3-ASR", url: "https://huggingface.co/Qwen/Qwen3-ASR-1.7B" },
    whisper: { name: "whisper.cpp", url: "https://github.com/ggerganov/whisper.cpp" },
    funasr: { name: "FunASR", url: "https://github.com/modelscope/FunASR" },
};
const asrEngineLinks = computed(() => {
    const keys = asrEngineKeys.value.length ? asrEngineKeys.value : ["whisper", "funasr"];
    return keys.map((k) => ASR_ENGINE_LINKS[k]).filter(Boolean);
});
const fetchAsrEngine = async () => {
    try {
        const res = await fetch(`${base_url}/system/asr-engine`);
        const data = await res.json();
        if (data?.display_name) asrEngineName.value = data.display_name;
        if (data?.mappings) asrEngineKeys.value = [...new Set(Object.values(data.mappings) as string[])].sort();
    } catch (e) {
        console.error("Error fetching ASR engine:", e);
    }
};

const fetchPrompts = async () => {
    try {
        const [cur, def] = await Promise.all([
            fetch(`${base_url}/settings/settings/prompts`).then((r) => r.json()),
            fetch(`${base_url}/settings/settings/prompts/default`).then((r) => r.json()),
        ]);
        if (cur) {
            current_prompt_en.value = cur.english_prompt;
            current_prompt_zh.value = cur.chinese_prompt;
        }
        if (def) {
            default_prompt_en.value = def.english_prompt;
            default_prompt_zh.value = def.chinese_prompt;
        }
    } catch (e) {
        console.error("Error fetching prompts:", e);
    }
};

const resetPrompt = (lang: string) => {
    if (lang === "en") current_prompt_en.value = default_prompt_en.value;
    else current_prompt_zh.value = default_prompt_zh.value;
};

// ---- 提交 / 取消 ----
const applySettings = async () => {
    loading.value = true;
    try {
        // 1. 持久化到本地 store
        settingsStore.$state.uiLanguage = uiLanguage.value;
        settingsStore.$state.language = recognitionLanguage.value;
        settingsStore.$state.role = role.value || "";
        settingsStore.$state.echoCancel = echoCancel.value;
        settingsStore.$state.inputDeviceIndex = inputDeviceIndex.value;
        settingsStore.$state.outputDeviceIndex = outputDeviceIndex.value;

        // 输出设备保存即生效（会话中修改下一句生效）
        await fetch(`${base_url}/system/audio-output-device`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ output_device_index: outputDeviceIndex.value }),
        });

        // 2. 下发 TTS 音色 + ASR 语言
        if (role.value) {
            const r1 = await fetch(`${base_url}/tts/models/load`, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ model_id: role.value }),
            });
            if (!r1.ok) throw new Error(`TTS load failed: ${r1.status}`);
        }
        const r2 = await fetch(`${base_url}/asr/instance/create`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ language: recognitionLanguage.value }),
        });
        if (!r2.ok) throw new Error(`ASR set failed: ${r2.status}`);

        // 3. 保存 Prompt
        await fetch(`${base_url}/settings/settings/prompts`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
                chinese_prompt: current_prompt_zh.value,
                english_prompt: current_prompt_en.value,
            }),
        });

        emit("update:open", false);
    } catch (err) {
        console.error("Error applying settings:", err);
        Modal.error({ title: t("common.error"), content: t("settings.applyFailed") });
    } finally {
        loading.value = false;
    }
};

const handleCancel = () => {
    // 还原本地状态与界面语言
    uiLanguage.value = (settingsStore.$state.uiLanguage as UiLocale) ?? "en";
    setUiLocale(uiLanguage.value);
    recognitionLanguage.value = settingsStore.$state.language || "zh";
    echoCancel.value = settingsStore.$state.echoCancel ?? true;
    inputDeviceIndex.value = settingsStore.$state.inputDeviceIndex ?? null;
    outputDeviceIndex.value = settingsStore.$state.outputDeviceIndex ?? null;
    role.value = settingsStore.$state.role || "";
    emit("update:open", false);
};

watch(
    () => props.open,
    (isOpen) => {
        if (isOpen) {
            activeTab.value = "main";
            uiLanguage.value = (settingsStore.$state.uiLanguage as UiLocale) ?? "en";
            fetchASRLanguages();
            fetchTTSRoles();
            fetchInputDevices();
            fetchPrompts();
            fetchAsrEngine();
        }
    }
);

// ---- 音色试听 ----
const currentPlayingId = ref<string | null>(null);
const currentAudio = ref<HTMLAudioElement | null>(null);
const isPlaying = (id: string) => currentPlayingId.value === id;

const playRefAudio = async (id: string, e: Event) => {
    e.stopPropagation();
    e.preventDefault();
    try {
        if (currentPlayingId.value === id && currentAudio.value) {
            currentAudio.value.pause();
            currentAudio.value = null;
            currentPlayingId.value = null;
            return;
        }
        if (currentAudio.value) {
            currentAudio.value.pause();
            currentAudio.value = null;
        }
        const audio = new Audio(`${base_url}/tts/models/${id}/reference-audio`);
        audio.addEventListener("ended", () => {
            currentPlayingId.value = null;
            currentAudio.value = null;
        });
        await audio.play();
        currentPlayingId.value = id;
        currentAudio.value = audio;
    } catch (err) {
        currentPlayingId.value = null;
        currentAudio.value = null;
    }
};

onUnmounted(() => {
    if (currentAudio.value) currentAudio.value.pause();
});
</script>

<template>
    <a-modal
        :open="props.open"
        :title="t('settings.title')"
        :mask-closable="false"
        :closable="true"
        :width="600"
        centered
        transition-name="ant-fade"
        @cancel="handleCancel"
        @update:open="(v: boolean) => emit('update:open', v)"
    >
        <template #footer>
            <a-button key="back" @click="handleCancel">{{ t('common.cancel') }}</a-button>
            <a-button key="confirm" type="primary" :loading="loading" @click="applySettings">
                {{ t('common.confirm') }}
            </a-button>
        </template>

        <a-tabs v-model:activeKey="activeTab" class="settings-tabs">
            <!-- 常用：输入源 + 回音消除 + 音色（大家最关心的） -->
            <a-tab-pane key="main" :tab="t('settings.tabs.main')">
                <div class="tab-body">
                    <div class="setting-row">
                        <label>{{ t('settings.audio.microphone') }}</label>
                        <a-select v-model:value="inputDeviceIndex" style="width: 100%;">
                            <a-select-option :value="null">{{ t('settings.audio.systemDefault') }}</a-select-option>
                            <a-select-option v-for="dev in inputDevices" :value="dev.index" :key="dev.index">
                                {{ dev.name }}<template v-if="dev.max_input_channels > 1"> ({{ dev.max_input_channels }}{{ t('settings.audio.channelsSuffix') }})</template><template v-if="dev.is_default"> · {{ t('settings.audio.defaultSuffix') }}</template>
                            </a-select-option>
                        </a-select>
                    </div>
                    <div class="setting-row">
                        <label>{{ t('settings.audio.speaker') }}</label>
                        <a-select v-model:value="outputDeviceIndex" style="width: 100%;">
                            <a-select-option :value="null">{{ t('settings.audio.systemDefault') }}</a-select-option>
                            <a-select-option v-for="dev in outputDevices" :value="dev.index" :key="dev.index">
                                {{ dev.name }}<template v-if="dev.is_default"> · {{ t('settings.audio.defaultSuffix') }}</template>
                            </a-select-option>
                        </a-select>
                    </div>
                    <div class="setting-row">
                        <div class="row-inline">
                            <label>{{ t('settings.audio.echoCancellation') }}</label>
                            <a-switch v-model:checked="echoCancel" />
                        </div>
                    </div>
                    <div class="setting-row">
                        <label>{{ t('settings.voice.role') }}</label>
                        <a-radio-group v-model:value="role" class="voice-group">
                            <a-radio v-for="r in filteredRoles" :value="r['id']" :key="r['id']" class="voice-radio">
                                <span class="voice-name">{{ r['character_name'] }}</span>
                                <a-button
                                    type="text"
                                    class="audio-play-btn"
                                    :class="{ playing: isPlaying(r['id']) }"
                                    @click="playRefAudio(r['id'], $event)"
                                >
                                    <SoundTwoTone v-if="isPlaying(r['id'])" style="font-size: 16px; color: #52c41a;" />
                                    <SoundOutlined v-else style="font-size: 16px; color: #1890ff;" />
                                </a-button>
                            </a-radio>
                        </a-radio-group>
                    </div>
                </div>
            </a-tab-pane>

            <!-- 语言：界面语言 + 识别语言 -->
            <a-tab-pane key="language" :tab="t('settings.tabs.language')">
                <div class="tab-body">
                    <div class="setting-row">
                        <label><TranslationOutlined class="label-icon" />{{ t('settings.general.interfaceLanguage') }}</label>
                        <a-select v-model:value="uiLanguage" style="width: 100%;">
                            <a-select-option value="zh">{{ t('lang.zh') }}</a-select-option>
                            <a-select-option value="en">{{ t('lang.en') }}</a-select-option>
                        </a-select>
                        <p class="hint">{{ t('settings.general.interfaceLanguageHint') }}</p>
                    </div>
                    <div class="setting-row">
                        <label><AudioOutlined class="label-icon" />{{ t('settings.recognition.language') }}</label>
                        <a-select v-model:value="recognitionLanguage" style="width: 100%;">
                            <a-select-option v-for="lan in languages" :value="lan" :key="lan">
                                {{ t('lang.' + lan) }}
                            </a-select-option>
                        </a-select>
                        <p class="hint">{{ t('settings.recognition.languageHint') }}</p>
                    </div>
                </div>
            </a-tab-pane>

            <!-- 高级：系统提示词 -->
            <a-tab-pane key="advanced" :tab="t('settings.tabs.advanced')">
                <div class="tab-body">
                    <div class="setting-row">
                        <label>{{ t('settings.prompt.title') }}</label>
                        <a-radio-group button-style="solid" size="small" v-model:value="promptLang" style="margin-bottom: 12px;">
                            <a-radio-button value="zh">{{ t('lang.zh') }}</a-radio-button>
                            <a-radio-button value="en">{{ t('lang.en') }}</a-radio-button>
                        </a-radio-group>
                        <div v-show="promptLang === 'zh'">
                            <a-textarea v-model:value="current_prompt_zh" :placeholder="default_prompt_zh"
                                :auto-size="{ minRows: 6, maxRows: 10 }" show-count :maxlength="2000" allow-clear />
                            <a-button size="small" @click="resetPrompt('zh')" style="margin-top: 12px;">{{ t('common.reset') }}</a-button>
                        </div>
                        <div v-show="promptLang === 'en'">
                            <a-textarea v-model:value="current_prompt_en" :placeholder="default_prompt_en"
                                :auto-size="{ minRows: 6, maxRows: 10 }" show-count :maxlength="2000" allow-clear />
                            <a-button size="small" @click="resetPrompt('en')" style="margin-top: 12px;">{{ t('common.reset') }}</a-button>
                        </div>
                    </div>
                </div>
            </a-tab-pane>

            <!-- 关于 -->
            <a-tab-pane key="about" :tab="t('settings.tabs.about')">
                <div class="tab-body about">
                    <div class="about-head">
                        <div class="about-name">Voice Dialogue</div>
                        <div class="about-ver">{{ t('settings.about.version') }} {{ appVersion }}</div>
                        <div class="about-tagline">{{ t('settings.about.tagline') }}</div>
                    </div>

                    <div class="about-section">
                        <div class="about-section-title">{{ t('settings.about.modelsTitle') }}</div>
                        <div class="about-item">
                            <div class="about-item-label">{{ t('settings.about.llm') }}</div>
                            <div class="about-item-desc">
                                {{ t('settings.about.llmDesc') }}
                                <a href="https://huggingface.co/Qwen/Qwen3-8B" target="_blank" rel="noopener">Qwen3 ↗</a>
                            </div>
                        </div>
                        <div class="about-item">
                            <div class="about-item-label">{{ t('settings.about.asr') }}</div>
                            <div class="about-item-desc">
                                {{ asrEngineName || t('settings.about.asrDesc') }}
                                <a v-for="link in asrEngineLinks" :key="link.url" :href="link.url" target="_blank"
                                    rel="noopener">{{ link.name }} ↗</a>
                            </div>
                        </div>
                        <div class="about-item">
                            <div class="about-item-label">{{ t('settings.about.tts') }}</div>
                            <div class="about-item-desc">
                                {{ t('settings.about.ttsDesc') }}
                                <a href="https://github.com/RVC-Boss/GPT-SoVITS" target="_blank" rel="noopener">GPT-SoVITS ↗</a>
                                <a href="https://huggingface.co/hexgrad/Kokoro-82M" target="_blank" rel="noopener">Kokoro ↗</a>
                            </div>
                        </div>
                    </div>

                    <div class="about-section">
                        <div class="about-section-title">{{ t('settings.about.linksTitle') }}</div>
                        <div class="about-item">
                            <div class="about-item-label">{{ t('settings.about.repoApp') }}</div>
                            <a class="about-link" href="https://huggingface.co/MoYoYoTech/VoiceDialogue" target="_blank" rel="noopener">huggingface.co/MoYoYoTech/VoiceDialogue</a>
                        </div>
                        <div class="about-item">
                            <div class="about-item-label">{{ t('settings.about.repoVoices') }}</div>
                            <a class="about-link" href="https://huggingface.co/MoYoYoTech/tone-models" target="_blank" rel="noopener">huggingface.co/MoYoYoTech/tone-models</a>
                        </div>
                    </div>

                    <div class="about-copyright">{{ t('settings.about.copyright') }}</div>
                </div>
            </a-tab-pane>
        </a-tabs>
    </a-modal>
</template>

<style lang="scss" scoped>
// 固定内容区高度，切换 Tab 时横条不再跳动
.tab-body {
    height: 360px;
    overflow-y: auto;
    padding: 4px 8px 4px 2px;
}

.setting-row {
    margin-bottom: 20px;

    // 仅作用于字段标题（直接子 label），避免影响嵌套的 radio-button 等 <label>
    > label {
        display: block;
        font-size: 15px;
        font-weight: 500;
        margin-bottom: 8px;

        .label-icon {
            margin-right: 6px;
            color: #1890ff;
        }
    }

    .hint {
        font-size: 12px;
        color: #999;
        margin: 8px 0 0;
    }

    .row-inline {
        display: flex;
        align-items: center;
        justify-content: space-between;
    }
}

.voice-group {
    display: flex;
    flex-direction: column;
    margin-top: 8px;
}

/* 关于页 */
.about {
    .about-head {
        text-align: center;
        margin-bottom: 24px;

        .about-name {
            font-size: 20px;
            font-weight: 600;
        }
        .about-ver {
            font-size: 13px;
            color: #888;
            margin-top: 2px;
        }
        .about-tagline {
            font-size: 12px;
            color: #999;
            margin-top: 4px;
        }
    }

    .about-section {
        margin-bottom: 20px;

        .about-section-title {
            font-size: 13px;
            font-weight: 600;
            color: #666;
            margin-bottom: 10px;
        }
    }

    .about-item {
        margin-bottom: 12px;

        .about-item-label {
            font-size: 14px;
            font-weight: 500;
        }
        .about-item-desc {
            font-size: 12px;
            color: #777;
            margin-top: 2px;
            line-height: 1.6;

            a { margin-left: 6px; }
        }
    }

    a {
        color: #1677ff;
        text-decoration: none;
        &:hover { text-decoration: underline; }
    }

    .about-link {
        font-size: 13px;
        word-break: break-all;
    }

    .about-copyright {
        margin-top: 16px;
        font-size: 11px;
        color: #aaa;
        text-align: center;
    }
}

.voice-radio {
    display: flex;
    align-items: center;
    height: 40px;
    line-height: 40px;

    .voice-name {
        margin-right: 8px;
    }
}

.audio-play-btn {
    padding: 0 6px;
    border-radius: 4px;

    &.playing {
        background-color: #f6ffed;
    }
}
</style>
