<template>
    <el-dialog :model-value="show" width="900" :fullscreen="isFullscreen" :close-on-click-modal="false" @close="close"
        :show-close="false">
        <template #header>
            <div class="jfd-header">
                <span class="jfd-title">{{ title }}</span>
                <div class="jfd-header-actions">
                    <el-button link circle @click="isFullscreen = !isFullscreen"
                        :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-tabs v-if="langKeys.length" v-model="activeTab" type="border-card">
            <el-tab-pane v-for="lang in langKeys" :key="lang" :label="lang" :name="lang">
                <el-scrollbar max-height="60vh">
                    <div class="jfd-content">
                        <NodeEditor v-for="sKey in getSectionKeys(lang)" :key="sKey" :parent="formData[lang]"
                            :field-key="sKey" :field-map="fieldMap" :depth="0" />
                    </div>
                </el-scrollbar>
            </el-tab-pane>
        </el-tabs>
        <el-empty v-else description="无数据" />

        <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 { ref, computed, watch, defineComponent, h, type PropType, type VNode, type Component } from 'vue'
import { Close, FullScreen, CopyDocument, Plus, Delete } from '@element-plus/icons-vue'
import {
    ElFormItem, ElInput, ElInputNumber, ElSwitch, ElButton,
    ElCollapse, ElCollapseItem, ElIcon
} from 'element-plus'

const props = withDefaults(defineProps<{
    show: boolean
    title?: string
    data: Record<string, any>
    fieldMap?: Record<string, string>
}>(), {
    show: false,
    title: '配置编辑',
    data: () => ({}),
    fieldMap: () => ({}),
})

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

const isFullscreen = ref(false)
const formData = ref<Record<string, any>>({})
const activeTab = ref('')

const langKeys = computed(() => Object.keys(formData.value))

function getSectionKeys(lang: string) {
    const langData = formData.value[lang]
    return langData && typeof langData === 'object' ? Object.keys(langData) : []
}

const itemTemplates: Record<string, any> = {}

function collectItemTemplates(data: any) {
    if (data === null || data === undefined) return
    if (Array.isArray(data)) {
        if (data.length > 0 && typeof data[0] === 'object' && !Array.isArray(data[0])) {
            for (const key of Object.keys(data[0])) {
                collectItemTemplates(data[0][key])
            }
        }
        data.forEach(item => collectItemTemplates(item))
    } else if (typeof data === 'object') {
        for (const key of Object.keys(data)) {
            const val = data[key]
            if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'object' && !Array.isArray(val[0])) {
                if (!itemTemplates[key]) {
                    itemTemplates[key] = createEmpty(val[0])
                }
            }
            collectItemTemplates(val)
        }
    }
}

watch(() => props.show, (val) => {
    if (val && props.data) {
        formData.value = JSON.parse(JSON.stringify(props.data))
        Object.keys(itemTemplates).forEach(k => delete itemTemplates[k])
        const firstLang = langKeys.value[0]
        if (firstLang) collectItemTemplates(formData.value[firstLang])
        activeTab.value = firstLang || ''
    }
}, { immediate: true })

function close() {
    isFullscreen.value = false
    emit('close')
}

function submit() {
    emit('submit', JSON.parse(JSON.stringify(formData.value)))
}

function createEmpty(template: any): any {
    if (typeof template === 'string') return ''
    if (typeof template === 'number') return 0
    if (typeof template === 'boolean') return false
    if (Array.isArray(template)) return []
    if (typeof template === 'object' && template !== null) {
        const obj: any = {}
        for (const k of Object.keys(template)) obj[k] = createEmpty(template[k])
        return obj
    }
    return ''
}

const NodeEditor: Component = defineComponent({
    name: 'NodeEditor',
    props: {
        parent: { type: Object as PropType<any>, required: true },
        fieldKey: { type: [String, Number] as PropType<string | number>, required: true },
        fieldMap: { type: Object as PropType<Record<string, string>>, default: () => ({}) },
        depth: { type: Number, default: 0 },
    },
    setup(p) {
        return () => {
            const value = p.parent[p.fieldKey]
            const key = p.fieldKey
            const fm = p.fieldMap
            const depth = p.depth
            const label = typeof key === 'string' ? (fm[key] || key) : `#${Number(key) + 1}`

            if (value === null || value === undefined) return null

            if (typeof value === 'boolean') {
                return h(ElFormItem, { label, class: 'jfd-form-item' }, () =>
                    h(ElSwitch, {
                        modelValue: value,
                        'onUpdate:modelValue': (v: any) => { p.parent[key] = v },
                    })
                )
            }

            if (typeof value === 'number') {
                return h(ElFormItem, { label, class: 'jfd-form-item' }, () =>
                    h(ElInputNumber, {
                        modelValue: value,
                        'onUpdate:modelValue': (v: number | undefined) => { p.parent[key] = v ?? 0 },
                        controlsPosition: 'right',
                    })
                )
            }

            if (typeof value === 'string') {
                const isLong = value.length > 50
                return h(ElFormItem, { label, class: 'jfd-form-item' }, () =>
                    h(ElInput, {
                        modelValue: value,
                        ...(isLong ? { type: 'textarea', autosize: { minRows: 2, maxRows: 6 } } : {}),
                        'onUpdate:modelValue': (v: string) => { p.parent[key] = v },
                    })
                )
            }

            if (Array.isArray(value)) {
                const keyStr = String(key)
                const hasLiveObj = value.length > 0 && typeof value[0] === 'object' && !Array.isArray(value[0])
                const savedTemplate = itemTemplates[keyStr]
                const isObjArr = hasLiveObj || !!savedTemplate

                if (!isObjArr) {
                    return h('div', { class: 'jfd-array-group' }, [
                        h('div', { class: 'jfd-group-header' }, [
                            h('span', { class: 'jfd-group-title' }, label),
                            h(ElButton, {
                                size: 'small', type: 'primary', link: true,
                                onClick: () => value.push(''),
                            }, () => [h(ElIcon, { size: 14 }, () => h(Plus)), ' 添加'])
                        ]),
                        ...value.map((_: any, i: number) =>
                            h('div', { class: 'jfd-string-item', key: i }, [
                                h(ElInput, {
                                    modelValue: value[i],
                                    'onUpdate:modelValue': (v: string) => { value[i] = v },
                                }),
                                h(ElButton, {
                                    size: 'small', type: 'danger', link: true,
                                    onClick: () => value.splice(i, 1),
                                }, () => h(ElIcon, { size: 14 }, () => h(Delete)))
                            ])
                        )
                    ])
                }

                const makeNewItem = () => {
                    const tpl = hasLiveObj ? value[0] : savedTemplate
                    return JSON.parse(JSON.stringify(tpl ? createEmpty(tpl) : {}))
                }

                return h('div', { class: 'jfd-array-group' }, [
                    h('div', { class: 'jfd-group-header' }, [
                        h('span', { class: 'jfd-group-title' }, label),
                        h(ElButton, {
                            size: 'small', type: 'primary', link: true,
                            onClick: () => value.push(makeNewItem()),
                        }, () => [h(ElIcon, { size: 14 }, () => h(Plus)), ' 添加'])
                    ]),
                    h(ElCollapse, { class: 'jfd-obj-array' }, () =>
                        value.map((item: any, i: number) => {
                            const tag = item.title || item.name || item.text || ''
                            return h(ElCollapseItem, {
                                title: `${label} #${i + 1}${tag ? ' - ' + tag : ''}`,
                                name: `${String(key)}-${i}`,
                                key: i,
                            }, () => [
                                ...Object.keys(item).map(k =>
                                    h(NodeEditor, { parent: item, fieldKey: k, fieldMap: fm, depth: depth + 1, key: k })
                                ),
                                h('div', { class: 'jfd-item-actions' },
                                    h(ElButton, {
                                        size: 'small', type: 'danger',
                                        onClick: () => value.splice(i, 1),
                                    }, () => [h(ElIcon, { size: 14 }, () => h(Delete)), ' 删除此项'])
                                )
                            ])
                        })
                    )
                ])
            }

            if (typeof value === 'object') {
                const children = Object.keys(value).map(k =>
                    h(NodeEditor, { parent: value, fieldKey: k, fieldMap: fm, depth: depth + 1, key: k })
                )

                if (depth === 0) {
                    return h('div', { class: 'jfd-section' }, [
                        h('div', { class: 'jfd-section-header' }, label),
                        h('div', { class: 'jfd-section-body' }, children)
                    ])
                }

                return h('div', { class: 'jfd-nested' }, [
                    h('div', { class: 'jfd-nested-title' }, label),
                    ...children
                ])
            }

            return null
        }
    }
})
</script>

<style lang="scss">
.jfd-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;

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

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

.jfd-content {
    padding: 12px;
}

.jfd-form-item {
    margin-bottom: 16px;
}

.jfd-section {
    margin-bottom: 16px;
    border: 1px solid var(--el-border-color);
    border-radius: 6px;
    overflow: hidden;
}

.jfd-section-header {
    padding: 10px 16px;
    font-weight: 600;
    font-size: 15px;
    background-color: var(--el-fill-color-light);
    border-bottom: 1px solid var(--el-border-color);
}

.jfd-section-body {
    padding: 16px;
}

.jfd-array-group {
    margin-bottom: 12px;
}

.jfd-group-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
    
}

.jfd-group-title {
    font-weight: 500;
    font-size: 14px;
    color: var(--el-text-color-primary);
}

.jfd-string-item {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 8px;
}

.jfd-item-actions {
    text-align: right;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--el-border-color-lighter);
}

.jfd-nested {
    margin-left: 12px;
    padding-left: 12px;
    border-left: 2px solid var(--el-border-color);
    margin-bottom: 12px;
}

.jfd-nested-title {
    font-weight: 500;
    font-size: 13px;
    color: var(--el-text-color-regular);
    margin-bottom: 8px;
}

.jfd-obj-array .el-collapse-item__header {
    font-size: 13px;
}
</style>
