<template>
    <el-dialog :model-value="show" width="800" :fullscreen="isFullscreen" :close-on-click-modal="false" @close="close"
        :show-close="false">
        <template #header>
            <div class="dialog-header">
                <span class="dialog-title">{{ title }}</span>
                <div class="dialog-header-actions">
                    <el-button link circle @click="toggleFullscreen" :title="isFullscreen ? '退出全屏' : '全屏'">
                        <el-icon>
                            <CopyDocument v-if="isFullscreen" />
                            <FullScreen v-else />
                        </el-icon>
                    </el-button>
                    <el-button link circle @click="close" title="关闭">
                        <el-icon size="18">
                            <Close />
                        </el-icon>
                    </el-button>
                </div>
            </div>
        </template>
        <el-form v-if="show" ref="formRef" :model="formData" :rules="formRules" label-position="left"
            v-loading="detailLoading">

            <div v-if="normalFields.length" class="in18-form-top">
                <el-form-item v-for="item in normalFields" :key="item.key" :prop="item.key">
                    <template #label>
                        {{ item.name }}
                    </template>
                    <el-input v-if="item.type === 'input'" v-model="formData[item.key]"
                        :placeholder="`请输入${item.name}`" />
                    <el-input v-else-if="item.type === 'textarea'" v-model="formData[item.key]" type="textarea"
                        :rows="4" :placeholder="`请输入${item.name}`" />
                    <el-select v-else-if="item.type === 'select'" v-model="formData[item.key]"
                        :placeholder="`请选择${item.name}`" clearable style="width: 100%">
                        <el-option v-for="opt in getSelectItems(item)" :key="opt.key" :label="opt.name"
                            :value="opt.key" />
                    </el-select>
                    <div v-else-if="isUploadMediaType(item.type)" style="width:100%;">
                        <div class="upload-group">
                            <div class="upload-label">图片</div>
                            <UploadInput :model-value="(formData[item.key]?.image || []).join(',')"
                                :type="item.type.includes('images') ? 'images' : 'image'"
                                :uploadFile="uploadFun" @update:modelValue="(val: string) => {
                                    if (!formData[item.key]) formData[item.key] = { image: [], video: [] };
                                    formData[item.key].image = val ? val.split(',').filter(Boolean) : [];
                                }" />
                        </div>
                        <div class="upload-group">
                            <div class="upload-label">视频</div>
                            <UploadInput :model-value="(formData[item.key]?.video || []).join(',')" type="video"
                                :uploadFile="uploadFun" @update:modelValue="(val: string) => {
                                    if (!formData[item.key]) formData[item.key] = { image: [], video: [] };
                                    formData[item.key].video = val ? val.split(',').filter(Boolean) : [];
                                }" />
                        </div>
                    </div>
                    <div v-else-if="item.type === 'upload:file'" style="width:100%;" class="upload-file">
                        <UploadInput :model-value="formData[item.key]" type="file" :accept="item.accept || '*'"
                            :uploadFile="uploadFun"
                            @update:modelValue="(val: string) => { formData[item.key] = val }" />
                    </div>
                </el-form-item>
            </div>

            <div class="in18-form-header">
                <div class="in18-form-header-left">
                    <span>{{ primaryLocale?.name }}</span>
                </div>
                <div class="in18-form-header-right">
                    <span v-for="locale in secondaryLocales" :key="locale.key" class="locale-tab"
                        :class="{ active: activeSecondaryLocale?.key === locale.key }"
                        @click="activeSecondaryLocale = locale">
                        {{ locale.name }}
                    </span>
                </div>
            </div>

            <div v-if="translateFields.length && secondaryLocales.length" class="in18-form-wrapper">
                <div class="in18-form-left">
                    <el-form-item v-for="item in translateFields" :key="item.key"
                        :prop="`translations.${primaryLocaleKey}.${item.key}`">
                        <template #label>
                            {{ item.name }}
                        </template>
                        <el-input v-if="item.type === 'input'"
                            v-model="formData.translations[primaryLocaleKey][item.key]"
                            :placeholder="`请输入${item.name}`" />
                        <el-input v-else-if="item.type === 'textarea'"
                            v-model="formData.translations[primaryLocaleKey][item.key]" type="textarea"
                            :rows="4" :placeholder="`请输入${item.name}`" />
                        <el-select v-else-if="item.type === 'select'"
                            v-model="formData.translations[primaryLocaleKey][item.key]"
                            :placeholder="`请选择${item.name}`" clearable style="width: 100%">
                            <el-option v-for="opt in getSelectItems(item)" :key="opt.key" :label="opt.name"
                                :value="opt.key" />
                        </el-select>
                    </el-form-item>
                </div>
                <div class="in18-form-center">
                    <el-button v-if="activeSecondaryLocale" type="primary" :loading="translating"
                        @click="handleTranslate">
                        翻译
                    </el-button>
                </div>
                <div v-if="activeSecondaryLocale" class="in18-form-right">
                    <el-form-item v-for="item in translateFields" :key="item.key">
                        <template #label>
                            {{ item.name }}
                        </template>
                        <div v-if="item.type === 'input' || item.type === 'textarea'" class="field-with-translate">
                            <el-input
                                v-model="formData.translations[activeSecondaryLocale?.key || ''][item.key]"
                                :type="item.type === 'textarea' ? 'textarea' : undefined"
                                :rows="item.type === 'textarea' ? 4 : undefined"
                                :placeholder="`请输入${item.name}`" />
                            <el-button link size="small" class="translate-icon"
                                :loading="translatingFieldKey === item.key" @click="handleTranslateField(item.key)"
                                title="翻译该字段">
                                <el-icon color="#409eff">
                                    <Promotion />
                                </el-icon>
                            </el-button>
                        </div>
                        <el-select v-else-if="item.type === 'select'"
                            v-model="formData.translations[activeSecondaryLocale?.key || ''][item.key]"
                            :placeholder="`请选择${item.name}`" clearable style="width: 100%">
                            <el-option v-for="opt in getSelectItems(item)" :key="opt.key" :label="opt.name"
                                :value="opt.key" />
                        </el-select>
                    </el-form-item>
                </div>
            </div>
        </el-form>

        <template #footer>
            <el-button @click="close">取消</el-button>
            <el-button type="primary" @click="submit">确认提交</el-button>
        </template>
    </el-dialog>
</template>

<script setup lang="ts">
import { reactive, computed, watch, ref, nextTick } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage } from 'element-plus'
import { Close, Promotion, FullScreen, CopyDocument } from '@element-plus/icons-vue'
import UploadInput from "lib/components/UploadInput.vue";

type FormItemType =
    | 'input'
    | 'select'
    | 'textarea'
    | 'upload:images,video'
    | 'upload:image,video'
    | 'upload:file'

type FormItem = {
    name: string
    key: string
    type: FormItemType
    value: string | number | { image: string[]; video: string[] }
    items?: { key: string; name: string }[]
    getItems?: () => { key: string; name: string }[]
    must?: boolean
    shouldTranslate?: boolean
    accept?: string
    [prop: string]: any
}

type LocaleItem = {
    name: string
    key: string
    isPrimary?: boolean
}

const props = withDefaults(
    defineProps<{
        show: boolean
        id: string | number
        title?: string
        form: FormItem[]
        locales: LocaleItem[]
        translateApi: (data: { text: string; from?: string; to?: string }) => Promise<any>
        detailApi: (id: number) => Promise<any>
        uploadFun?: (formData: FormData) => Promise<any>
    }>(),
    {
        show: false,
        id: '',
        title: '详情',
        form: () => [],
        locales: () => [],
        translateApi: () => Promise.reject({ code: 500, message: 'translateApi not implemented' }),
        detailApi: () => Promise.reject({ code: 500, message: 'detailApi not implemented' }),
        uploadFun: () => Promise.reject({ code: 500, message: 'uploadFun not implemented' }),
    }
)

const emit = defineEmits(['close', 'submit'])

const primaryLocale = computed(() => props.locales.find((l) => l.isPrimary) || props.locales[0])
const primaryLocaleKey = computed(() => primaryLocale.value?.key || 'ZH')
const secondaryLocales = computed(() => props.locales.filter((l) => !l.isPrimary))
const activeSecondaryLocale = ref<LocaleItem | null>(null)
const normalFields = computed(() => props.form.filter((f) => !f.shouldTranslate))
const translateFields = computed(() => props.form.filter((f) => f.shouldTranslate))

function isUploadMediaType(type: string): boolean {
    return type === 'upload:images,video' || type === 'upload:image,video'
}

function getSelectItems(item: FormItem): { key: string; name: string }[] {
    return item.items ?? item.getItems?.() ?? []
}

function parseTranslateResult(res: any): string {
    return res?.data?.text ?? res?.data ?? res?.result ?? (typeof res === 'string' ? res : '')
}

const formRef = ref<FormInstance>()

const formRules = computed<FormRules>(() => {
    const rules: FormRules = {}
    normalFields.value.forEach((item) => {
        if (item.must) {
            rules[item.key] = [{ required: true, message: `请输入${item.name}`, trigger: ['blur', 'change'] }]
        }
    })
    translateFields.value.forEach((item) => {
        if (item.must) {
            const prop = `translations.${primaryLocaleKey.value}.${item.key}`
            rules[prop] = [{ required: true, message: `请输入${item.name}`, trigger: ['blur', 'change'] }]
        }
    })
    return rules
})

const formData = reactive<{
    [key: string]: any
    translations: Record<string, Record<string, any>>
}>({
    translations: {}
})

const translating = ref(false)
const translatingFieldKey = ref<string>('')
const isFullscreen = ref(false)
const detailLoading = ref(false)

function toggleFullscreen() {
    isFullscreen.value = !isFullscreen.value
}

function resetFormData() {
    Object.keys(formData).forEach((k) => {
        if (k !== 'translations') delete formData[k]
    })
    formData.translations = {}
}

function initFormData() {
    const normal: Record<string, any> = {}
    const translations: Record<string, Record<string, any>> = {}

    props.form.forEach((item) => {
        if (item.shouldTranslate) {
            props.locales.forEach((locale) => {
                if (!translations[locale.key]) translations[locale.key] = {}
                translations[locale.key][item.key] = item.value ?? ''
            })
        } else if (isUploadMediaType(item.type)) {
            const val: any = item.value
            normal[item.key] = (val && typeof val === 'object' && Array.isArray(val.image) && Array.isArray(val.video))
                ? val
                : { image: [], video: [] }
        } else {
            normal[item.key] = item.value ?? ''
        }
    })

    Object.keys(formData).forEach((k) => {
        if (k !== 'translations') delete formData[k]
    })
    Object.keys(normal).forEach((k) => {
        formData[k] = normal[k]
    })
    formData.translations = translations

    if (secondaryLocales.value.length > 0 && !activeSecondaryLocale.value) {
        activeSecondaryLocale.value = secondaryLocales.value[0]
    } else if (secondaryLocales.value.length > 0) {
        const stillExists = secondaryLocales.value.some((l) => l.key === activeSecondaryLocale.value?.key)
        if (!stillExists) {
            activeSecondaryLocale.value = secondaryLocales.value[0]
        }
    } else {
        activeSecondaryLocale.value = null
    }
    nextTick(() => formRef.value?.clearValidate())
}

watch(
    () => [props.show, props.form, props.locales],
    async () => {
        if (props.show) {
            initFormData()
            if (props.id) {
                detailLoading.value = true
                try {
                    const data = await props.detailApi(Number(props.id))
                    if (data) {
                        const pKey = primaryLocaleKey.value
                        Object.keys(data).forEach((localeKey) => {
                            const localeData = data[localeKey]
                            if (!localeData || typeof localeData !== 'object' || !props.locales.some((l) => l.key === localeKey)) return
                            Object.keys(localeData).forEach((fieldKey) => {
                                const field = props.form.find((f) => f.key === fieldKey)
                                if (!field) return
                                if (field.shouldTranslate) {
                                    if (!formData.translations[localeKey]) formData.translations[localeKey] = {}
                                    formData.translations[localeKey][fieldKey] = localeData[fieldKey]
                                } else if (localeKey === pKey) {
                                    formData[fieldKey] = localeData[fieldKey]
                                }
                            })
                        })
                    }
                } catch (e) {
                    console.error('Failed to load detail:', e)
                    ElMessage.error('加载详情失败')
                } finally {
                    detailLoading.value = false
                }
            }
        }
    },
    { immediate: true, deep: true }
)

const close = () => {
    isFullscreen.value = false
    resetFormData()
    emit('close')
}

async function handleTranslate() {
    if (!primaryLocale.value || !activeSecondaryLocale.value || translating.value) return

    const fromKey = primaryLocale.value.key
    const toKey = activeSecondaryLocale.value.key
    const texts: { key: string; text: string }[] = []

    translateFields.value.forEach((item) => {
        const val = formData.translations?.[fromKey]?.[item.key]
        if (val != null && String(val).trim()) {
            texts.push({ key: item.key, text: String(val).trim() })
        }
    })

    if (texts.length === 0) return

    translating.value = true
    try {
        const results = await Promise.allSettled(
            texts.map(async ({ key, text }) => {
                const res = await props.translateApi({ text, from: fromKey, to: toKey })
                return { key, translated: parseTranslateResult(res) }
            })
        )
        let failCount = 0
        for (const result of results) {
            if (result.status === 'fulfilled') {
                const { key, translated } = result.value
                if (formData.translations[toKey]) {
                    formData.translations[toKey][key] = translated
                }
            } else {
                failCount++
            }
        }
        if (failCount > 0) {
            ElMessage.warning(`${failCount} 个字段翻译失败`)
        }
    } catch (e) {
        console.error('Translate failed:', e)
        ElMessage.error('翻译失败')
    } finally {
        translating.value = false
    }
}

async function handleTranslateField(itemKey: string) {
    if (!primaryLocale.value || !activeSecondaryLocale.value || translatingFieldKey.value) return
    const fromKey = primaryLocale.value.key
    const toKey = activeSecondaryLocale.value.key
    const text = formData.translations?.[fromKey]?.[itemKey]
    if (text == null || !String(text).trim()) return
    translatingFieldKey.value = itemKey
    try {
        const res = await props.translateApi({ text: String(text).trim(), from: fromKey, to: toKey })
        if (formData.translations[toKey]) formData.translations[toKey][itemKey] = parseTranslateResult(res)
    } catch (e) {
        console.error('Translate failed:', e)
        ElMessage.error('翻译失败')
    } finally {
        translatingFieldKey.value = ''
    }
}

async function submit() {
    try {
        await formRef.value?.validate()
    } catch {
        return
    }
    const data: Record<string, any> = { id: props.id || '' }
    normalFields.value.forEach((item) => {
        data[item.key] = formData[item.key]
    })
    if (Object.keys(formData.translations || {}).length > 0) {
        data.translations = formData.translations
    }
    emit('submit', data)
}
</script>

<style scoped lang="scss">
.dialog-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding-right: 40px;

    .dialog-title {
        font-size: 18px;
        font-weight: 500;
    }

    .dialog-header-actions {
        display: flex;
        gap: 4px;
    }
}

.in18-form-header {
    display: flex;
    border-bottom: 1px solid var(--el-border-color);

    .in18-form-header-left,
    .in18-form-header-right {
        flex: 1;
        padding: 15px;
        font-weight: 500;
    }

    .in18-form-header-right {
        display: flex;
        gap: 8px;
        align-items: center;

        .locale-tab {
            padding: 5px 12px;
            border: 1px solid var(--el-border-color);
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;

            &.active {
                background-color: var(--el-color-primary);
                color: #fff;
                border-color: var(--el-color-primary);
            }

            &:hover:not(.active) {
                background-color: var(--el-fill-color-light);
            }
        }
    }
}

.in18-form-top {
    padding: 15px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;

    :deep(.el-form-item) {
        width: 100%;
        max-width: 400px;
        margin-bottom: 0;
    }
}

.in18-form-wrapper {
    display: flex;
    flex-direction: row;
    min-height: 200px;
    border-bottom: 1px solid var(--el-border-color);

    .in18-form-left,
    .in18-form-right {
        flex: 1;
        padding: 15px;
        overflow-y: auto;

        :deep(.el-form-item) {
            margin-bottom: 16px;
        }
    }

    .in18-form-left {
        border-right: 1px solid var(--el-border-color);
    }

    .field-with-translate {
        display: flex;
        align-items: flex-start;
        gap: 8px;
        width: 100%;

        .el-input,
        .el-textarea {
            flex: 1;
        }

        .translate-icon {
            flex-shrink: 0;
            padding: 8px 0;
        }
    }

    .in18-form-center {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0 15px;
        min-width: 80px;
        border-right: 1px solid var(--el-border-color);
    }
}
</style>
