<template>
    <el-dialog
        draggable
        width="520px"
        v-model.trim="dialogVisible"
        :title="title"
        :close-on-click-modal="!mqttProgressing"
        @closed="onClosed"
    >
        <el-form :model="form" class="form-one" label-width="auto" ref="formRef" :rules="rules">
            <el-form-item label="版本" prop="edDataId">
                <el-select
                    v-model.trim="form.edDataId"
                    placeholder="请选择版本"
                    :disabled="mqttProgressing"
                    @change="selectChange"
                >
                    <el-option
                        v-for="item in devList"
                        :key="item.id"
                        :disabled="version == item.versionNo"
                        :label="formatVersionLabel(item)"
                        :value="item.id"
                    ></el-option>
                </el-select>
            </el-form-item>

            <el-form-item label="描述">
                <el-input
                    maxlength="300"
                    show-word-limit
                    v-model.trim="versionDesc"
                    disabled
                    type="textarea"
                    :rows="3"
                ></el-input>
            </el-form-item>
        </el-form>

        <!-- 仅 MQTT：上传成功后在输入框下方显示升级进度 -->
        <div v-if="mqttVisible" class="mqtt-upgrade">
            <div class="mqtt-upgrade__label">升级版本</div>
            <el-progress
                :percentage="mqttProgress"
                :stroke-width="12"
                striped
                striped-flow
                :status="mqttProgress >= 100 ? 'success' : undefined"
            />

            <template v-if="mqttProgress >= 100">
                <div class="mqtt-upgrade__codes">
                    <div>升级文件校验码：{{ deviceCrc || '-' }}</div>
                    <div>归档文件校验码：{{ verifyCode || '获取中...' }}</div>
                </div>

                <div v-if="codeReady" class="mqtt-upgrade__actions">
                    <template v-if="codeMatched">
                        <el-button type="primary" :loading="confirmLoading" @click="confirmUpgrade">确认升级</el-button>
                        <el-button @click="cancelUpgrade">取消升级</el-button>
                    </template>
                    <el-alert v-else type="error" show-icon :closable="false" title="校验码不一致不能升级" />
                </div>
            </template>
        </div>

        <template #footer>
            <span class="dialog-footer">
                <el-button @click="handleCancel" :disabled="confirmLoading">取消</el-button>
                <el-button v-if="!mqttVisible" type="primary" @click="submit" :loading="loading">确定</el-button>
            </span>
        </template>
    </el-dialog>
</template>

<script lang="ts" setup>
import { ref, reactive, computed, onBeforeUnmount } from 'vue'
import { ElMessage } from 'element-plus'
import { findByDevTypeId, upgrade, uploadUpgradeFile, commitUpgradeFile } from '@/api/system-boot/dictTree'
import MqttService, { createMqttClient, calcMqttProgress } from '@/utils/MQTT'

const formRef = ref()
const dialogVisible = ref(false)
const title = ref('程序版本')
const devList: any = ref([])
const versionDesc = ref('')
const version = ref('')
const form = reactive<any>({
    devId: [] as any[],
    edDataId: ''
})
const loading = ref(false)
const rules = {
    edDataId: [{ required: true, message: '请选择版本', trigger: 'change' }]
}
const row = ref<any>({})

/** MQTT 升级进度 */
const mqttVisible = ref(false)
const mqttProgress = ref(0)
/** 升级文件校验码 = mqtt.devCrc */
const deviceCrc = ref('')
/** 归档文件校验码 = mqtt.systemCrc */
const verifyCode = ref('')
/** mqtt crcCheck 带回的 mid / version，确认升级用 */
const mqttMid = ref<string | number>('')
const mqttVersion = ref('')
const confirmLoading = ref(false)
const mqttService = ref<MqttService | null>(null)

const mqttProgressing = computed(() => mqttVisible.value && mqttProgress.value < 100)
const codeReady = computed(() => !!(deviceCrc.value && verifyCode.value))
const codeMatched = computed(() => codeReady.value && String(deviceCrc.value) === String(verifyCode.value))

const getDevIdStr = () => (Array.isArray(form.devId) ? form.devId.join() : String(form.devId || ''))

const open = (data: any) => {
    resetMqttState()
    loading.value = false
    version.value = data.version
    form.edDataId = ''
    versionDesc.value = ''
    row.value = data
    form.devId = Array.isArray(data.id) ? data.id : [data.id]
    getFindByDev(data.devModel)
    formRef.value?.resetFields()
    dialogVisible.value = true
}

const getFindByDev = (devModel: string) => {
    findByDevTypeId({
        devType: devModel,
        pageNum: 1,
        pageSize: 10000
    }).then((res: any) => {
        devList.value = res.data.records
        if (devList.value.length == 0) {
            ElMessage.warning('该设备没有可升级的版本!')
            return
        } else if (devList.value.length == 1 && devList.value[0].versionNo == version.value) {
            ElMessage.warning('该设备没有可升级的版本!')
        }
    })
}

function disconnectMqtt() {
    mqttService.value?.disconnect()
    mqttService.value = null
}

function resetMqttState() {
    disconnectMqtt()
    mqttVisible.value = false
    mqttProgress.value = 0
    deviceCrc.value = ''
    verifyCode.value = ''
    mqttMid.value = ''
    mqttVersion.value = ''
    confirmLoading.value = false
}

function connectUpgradeMqtt(ndid: string) {
    try {
        const topic = `/Web/Progress/UpgradeFile/${ndid}`
        mqttService.value = createMqttClient(topic, (_topic, data) => {
            // 进度消息
            if (data?.allStep != null || data?.nowStep != null) {
                mqttProgress.value = calcMqttProgress(data)
            }

            // type=crcCheck 时取校验码及确认升级参数
            if (data?.type === 'crcCheck') {
                mqttProgress.value = 100
                deviceCrc.value = data.devCrc != null ? String(data.devCrc) : ''
                verifyCode.value = data.systemCrc != null ? String(data.systemCrc) : ''
                mqttMid.value = data.mid ?? ''
                mqttVersion.value = data.version != null ? String(data.version) : ''
            }
        })
    } catch (e: any) {
        ElMessage.error(e?.message || 'MQTT 连接失败')
    }
}

const submit = () => {
    formRef.value.validate(async (valid: boolean) => {
        if (!valid) return
        try {
            loading.value = true
            if (row.value.accessMethod == 'CLD') {
                ElMessage.info('升级中，请稍等...')
                upgrade({
                    devId: getDevIdStr(),
                    edDataId: form.edDataId
                })
                    .then(res => {
                        ElMessage.success(res.message)
                        dialogVisible.value = false
                    })
                    .catch(() => {})
                    .finally(() => {
                        loading.value = false
                    })
            } else if (row.value.accessMethod == 'MQTT') {
                ElMessage.info('正在上传升级文件...')
                uploadUpgradeFile({
                    id: getDevIdStr(),
                    ndid: row.value.ndid
                })
                    .then(res => {
                        ElMessage.success(res.message || '上传成功')
                        loading.value = false
                        mqttVisible.value = true
                        mqttProgress.value = 0
                        deviceCrc.value = ''
                        verifyCode.value = ''
                        mqttMid.value = ''
                        mqttVersion.value = ''
                        connectUpgradeMqtt(row.value.ndid)
                    })
                    .catch(() => {
                        loading.value = false
                    })
            } else {
                ElMessage.warning('未知的接入方式')
                loading.value = false
            }
        } catch (error) {
            loading.value = false
        }
    })
}

const confirmUpgrade = () => {
    if (!codeMatched.value) {
        ElMessage.warning('校验码不一致不能升级')
        return
    }
    if (mqttMid.value === '' || mqttMid.value == null || !mqttVersion.value) {
        ElMessage.warning('未获取到升级参数，请稍后重试')
        return
    }
    confirmLoading.value = true
    commitUpgradeFile({
        mid: mqttMid.value,
        version: mqttVersion.value,
        nDid: row.value.ndid
    })
        .then((res: any) => {
            ElMessage.success(res.message || '升级成功')
            dialogVisible.value = false
        })
        .catch(() => {})
        .finally(() => {
            confirmLoading.value = false
        })
}

const cancelUpgrade = () => {
    resetMqttState()
    ElMessage.info('已取消升级')
}

const handleCancel = () => {
    if (mqttVisible.value) {
        cancelUpgrade()
    }
    dialogVisible.value = false
}

const selectChange = (e: string) => {
    const item = devList.value.find((v: any) => v.id === e)
    versionDesc.value = item?.description || ''
}

const formatVersionLabel = (item: any) => {
    const label = `${item.devTypeName}_${item.versionNo}_${item.versionAgreement}_${item.versionDate}`
    return version.value == item.versionNo ? `${label}(当前版本)` : label
}

const onClosed = () => {
    resetMqttState()
    loading.value = false
}

onBeforeUnmount(() => {
    disconnectMqtt()
})

defineExpose({ open })
</script>

<style scoped lang="scss">
.mqtt-upgrade {
    margin-top: 8px;
    padding-top: 12px;
    border-top: 1px solid var(--el-border-color-lighter);

    &__label {
        margin-bottom: 8px;
        font-size: 14px;
        font-weight: 600;
        color: #1d2129;
    }

    &__codes {
        margin-top: 14px;
        display: flex;
        flex-direction: column;
        gap: 8px;
        font-size: 13px;
        color: #4e5969;
        line-height: 1.5;
    }

    &__actions {
        margin-top: 14px;
        display: flex;
        align-items: center;
        gap: 10px;
    }
}
</style>
