<template>
    <el-dialog
        :model-value="visible"
        title="人工确认索引配置"
        width="960px"
        destroy-on-close
        top="6vh"
        class="mapping-confirm-dialog"
        @close="emit('update:visible', false)"
    >
        <div class="dialog-description">
            这里展示 ICD 候选索引的人工确认结果。请按分组确认每个标签是否启用，并为已启用标签选择合法的
            lnInst，确认后会自动回填到 request.indexSelection。
        </div>

        <el-empty v-if="!draftGroups.length" description="当前没有可确认的索引分组。" />

        <div v-else class="dialog-content">
            <section v-for="group in draftGroups" :key="group.groupKey" class="group-card">
                <div class="group-header">
                    <div>
                        <h3 class="group-title">{{ group.groupDesc || group.groupKey }}</h3>
                        <p class="group-key">{{ group.groupKey }}</p>
                    </div>
                    <el-tag type="info" effect="light">{{ group.labelItems.length }} 个标签</el-tag>
                </div>

                <div class="label-list">
                    <article v-for="item in group.labelItems" :key="`${group.groupKey}-${item.label}`" class="label-card">
                        <div class="label-main">
                            <div class="label-meta">
                                <div class="label-title-row">
                                    <span class="label-title">{{ item.label }}</span>
                                    <el-tag v-if="item.required" type="danger" effect="light" size="small">必选</el-tag>
                                    <el-tag v-if="item.configurableOnce" type="success" effect="light" size="small">
                                        共享 lnInst
                                    </el-tag>
                                </div>
                                <div class="label-options">
                                    <span class="label-hint">共同可选值</span>
                                    <template v-if="item.commonLnInstValues.length">
                                        <el-tag
                                            v-for="value in item.commonLnInstValues"
                                            :key="`${item.label}-${value}`"
                                            size="small"
                                            effect="plain"
                                        >
                                            {{ value }}
                                        </el-tag>
                                    </template>
                                    <span v-else class="label-hint">当前没有共同 lnInst</span>
                                </div>
                            </div>

                            <div class="label-actions">
                                <el-switch
                                    v-model="item.enabled"
                                    :disabled="item.required"
                                    inline-prompt
                                    active-text="启用"
                                    inactive-text="停用"
                                />
                                <el-select
                                    v-model="item.lnInst"
                                    class="lninst-select"
                                    placeholder="请选择 lnInst"
                                    clearable
                                    :disabled="!item.enabled || !item.commonLnInstValues.length"
                                >
                                    <el-option
                                        v-for="value in item.commonLnInstValues"
                                        :key="`${item.label}-option-${value}`"
                                        :label="value"
                                        :value="value"
                                    />
                                </el-select>
                            </div>
                        </div>

                        <el-alert
                            v-if="item.enabled && !item.lnInst"
                            title="已启用的标签必须选择 lnInst"
                            type="warning"
                            :closable="false"
                            class="label-alert"
                        />

                        <div class="target-list">
                            <div v-for="target in item.targets" :key="`${target.reportName}-${target.dataSetName}`" class="target-item">
                                <div class="target-name-row">
                                    <span class="target-name">{{ target.reportDesc || target.reportName || '--' }}</span>
                                    <span class="target-code">{{ target.reportName || '--' }} / {{ target.dataSetName || '--' }}</span>
                                </div>
                                <div class="target-lninst-row">
                                    <span class="label-hint">目标报告可选值</span>
                                    <template v-if="target.availableLnInstValues.length">
                                        <el-tag
                                            v-for="value in target.availableLnInstValues"
                                            :key="`${target.reportName}-${target.dataSetName}-${value}`"
                                            size="small"
                                            effect="plain"
                                        >
                                            {{ value }}
                                        </el-tag>
                                    </template>
                                    <span v-else class="label-hint">当前没有可用 lnInst</span>
                                </div>
                            </div>
                        </div>
                    </article>
                </div>
            </section>
        </div>

        <template #footer>
            <div class="dialog-footer">
                <div v-if="validationMessage" class="footer-message">{{ validationMessage }}</div>
                <div class="footer-actions">
                    <el-button :disabled="submitting" @click="emit('update:visible', false)">取消</el-button>
                    <el-button type="primary" :loading="submitting" :disabled="Boolean(validationMessage)" @click="handleConfirm">
                        确认并生成索引配置
                    </el-button>
                </div>
            </div>
        </template>
    </el-dialog>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import type { MmsMapping } from '@/api/tools/mmsmapping/interface'

defineOptions({
    name: 'MappingConfirmDialog'
})

interface ConfirmDialogDraftTarget {
    reportName: string
    dataSetName: string
    reportDesc: string
    availableLnInstValues: string[]
}

interface ConfirmDialogDraftLabelItem {
    label: string
    required: boolean
    configurableOnce: boolean
    enabled: boolean
    lnInst: string
    commonLnInstValues: string[]
    targets: ConfirmDialogDraftTarget[]
}

interface ConfirmDialogDraftGroup {
    groupKey: string
    groupDesc: string
    labelItems: ConfirmDialogDraftLabelItem[]
}

interface PreparedConfirmDialogDraftLabelItem {
    label: string
    required: boolean
    configurableOnce: boolean
    commonLnInstValues: string[]
    targets: ConfirmDialogDraftTarget[]
}

const props = defineProps<{
    visible: boolean
    submitting: boolean
    confirmData: MmsMapping.IndexConfirmGroup[]
}>()

const emit = defineEmits<{
    (event: 'update:visible', value: boolean): void
    (event: 'confirm', value: MmsMapping.ConfirmedIndexGroup[]): void
}>()

const normalizeStringArray = (values?: string[]) => (values || []).map(value => value?.trim() || '').filter(Boolean)

const sortLnInstValues = (values: string[]) =>
    [...values].sort((left, right) => {
        const leftNumber = Number(left)
        const rightNumber = Number(right)
        const bothNumeric = !Number.isNaN(leftNumber) && !Number.isNaN(rightNumber)

        if (bothNumeric && leftNumber !== rightNumber) {
            return leftNumber - rightNumber
        }

        return left.localeCompare(right, 'zh-CN', { numeric: true })
    })

const buildLnInstCluster = (items: PreparedConfirmDialogDraftLabelItem[]) => {
    const clusters: PreparedConfirmDialogDraftLabelItem[][] = []

    items.forEach(item => {
        const itemValueSet = new Set(item.commonLnInstValues)
        const matchedCluster = clusters.find(cluster =>
            cluster.some(clusterItem => clusterItem.commonLnInstValues.some(value => itemValueSet.has(value)))
        )

        if (matchedCluster) {
            matchedCluster.push(item)
            return
        }

        clusters.push([item])
    })

    return clusters
}

const resolveDefaultLnInst = (commonLnInstValues: string[], expectedLnInst: string) => {
    if (!commonLnInstValues.length) return ''
    if (!expectedLnInst) return ''
    if (!commonLnInstValues.includes(expectedLnInst)) return ''
    return expectedLnInst
}

const buildInitialDraftGroups = (groups: MmsMapping.IndexConfirmGroup[]): ConfirmDialogDraftGroup[] =>
    groups
        .map(group => {
            const preparedItems = (group.labelItems || [])
                .map<PreparedConfirmDialogDraftLabelItem | null>(item => {
                    const commonLnInstValues = sortLnInstValues(normalizeStringArray(item.commonLnInstValues))

                    return {
                        label: item.label?.trim() || '',
                        required: Boolean(item.required),
                        configurableOnce: Boolean(item.configurableOnce),
                        commonLnInstValues,
                        targets: (item.targets || []).map(target => ({
                            reportName: target.reportName?.trim() || '',
                            dataSetName: target.dataSetName?.trim() || '',
                            reportDesc: target.reportDesc?.trim() || '',
                            availableLnInstValues: sortLnInstValues(normalizeStringArray(target.availableLnInstValues))
                        }))
                    }
                })
                .filter((item): item is PreparedConfirmDialogDraftLabelItem => Boolean(item?.label))

            const clusters = buildLnInstCluster(preparedItems)
            const defaultStateMap = new Map<
                string,
                {
                    enabled: boolean
                    lnInst: string
                }
            >()

            clusters.forEach(cluster => {
                const clusterValues = sortLnInstValues(
                    Array.from(new Set(cluster.flatMap(item => item.commonLnInstValues)))
                )

                cluster.forEach((item, index) => {
                    const expectedLnInst = index < clusterValues.length ? clusterValues[index] : ''
                    const defaultLnInst = resolveDefaultLnInst(item.commonLnInstValues, expectedLnInst)
                    const enabled = Boolean(defaultLnInst)

                    defaultStateMap.set(item.label, {
                        enabled,
                        lnInst: defaultLnInst
                    })
                })
            })

            return {
                groupKey: group.groupKey?.trim() || '',
                groupDesc: group.groupDesc?.trim() || '',
                labelItems: preparedItems.map(item => {
                    const defaultState = defaultStateMap.get(item.label) || {
                        enabled: false,
                        lnInst: ''
                    }

                    return {
                        label: item.label,
                        required: item.required,
                        configurableOnce: item.configurableOnce,
                        enabled: defaultState.enabled,
                        lnInst: defaultState.lnInst,
                        commonLnInstValues: item.commonLnInstValues,
                        targets: item.targets
                    }
                })
            }
        })
        .filter(group => group.groupKey)

const draftGroups = ref<ConfirmDialogDraftGroup[]>([])

watch(
    () => [props.confirmData, props.visible] as const,
    ([confirmData, visible]) => {
        if (!visible) return
        // 关键业务节点：弹窗每次打开都基于最新 confirmData 重新生成草稿，避免不同 ICD 的确认状态串用。
        draftGroups.value = buildInitialDraftGroups(confirmData)
    },
    { immediate: true }
)

const validationMessage = computed(() => {
    for (const group of draftGroups.value) {
        for (const item of group.labelItems) {
            if (!item.enabled) continue
            if (!item.lnInst) return `分组“${group.groupDesc || group.groupKey}”中的标签“${item.label}”必须选择 lnInst`
        }
    }

    return ''
})

const buildConfirmedGroups = (): MmsMapping.ConfirmedIndexGroup[] =>
    draftGroups.value.map(group => ({
        groupKey: group.groupKey,
        labelItems: group.labelItems.map(item => ({
            label: item.label,
            enabled: item.enabled,
            lnInst: item.enabled ? item.lnInst : ''
        }))
    }))

const handleConfirm = () => {
    if (validationMessage.value) return
    emit('confirm', buildConfirmedGroups())
}
</script>

<style scoped lang="scss">
.dialog-description {
    margin-bottom: 16px;
    font-size: 14px;
    line-height: 1.7;
    color: #4b5563;
}

.dialog-content {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-height: 68vh;
    padding-right: 4px;
    overflow: auto;
}

.group-card {
    padding: 20px;
    border: 1px solid #dbe3f0;
    border-radius: 14px;
    background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
}

.group-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 16px;
}

.group-title {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    line-height: 1.5;
    color: #1f2937;
}

.group-key {
    margin: 6px 0 0;
    font-size: 12px;
    line-height: 1.6;
    color: #64748b;
    word-break: break-all;
}

.label-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.label-card {
    padding: 16px;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    background: #ffffff;
}

.label-main {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
}

.label-meta,
.label-actions,
.target-list {
    min-width: 0;
}

.label-meta {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 12px;
}

.label-title-row,
.label-options,
.target-lninst-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.label-title {
    font-size: 16px;
    font-weight: 600;
    line-height: 1.5;
    color: #111827;
}

.label-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
}

.lninst-select {
    width: 180px;
}

.label-hint {
    font-size: 13px;
    line-height: 1.6;
    color: #64748b;
}

.label-alert {
    margin-top: 12px;
}

.target-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 16px;
}

.target-item {
    padding: 12px;
    border-radius: 10px;
    background: #f8fafc;
}

.target-name-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}

.target-name {
    font-size: 14px;
    font-weight: 600;
    line-height: 1.6;
    color: #1f2937;
}

.target-code {
    font-family: Consolas, 'Courier New', monospace;
    font-size: 12px;
    line-height: 1.6;
    color: #64748b;
    word-break: break-all;
}

.dialog-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.footer-message {
    font-size: 13px;
    line-height: 1.6;
    color: #d97706;
    text-align: left;
}

.footer-actions {
    display: flex;
    gap: 12px;
    margin-left: auto;
}

@media (max-width: 768px) {
    .dialog-content {
        max-height: 62vh;
    }

    .group-card,
    .label-card {
        padding: 14px;
    }

    .group-header,
    .label-main,
    .dialog-footer {
        flex-direction: column;
        align-items: flex-start;
    }

    .label-actions,
    .footer-actions {
        width: 100%;
    }

    .lninst-select {
        width: 100%;
    }
}
</style>
