<script setup lang="ts">
import { detailMediaServerApi, detailVideoServerApi, icmpEntityByDeviceId, updateMediaServerApi, updateVideoServerApi, type NdmServerResultVO, type NdmServerUpdateVO, type Station } from '@/apis';
import { DEVICE_TYPE_LITERALS, tryGetDeviceType } from '@/enums';
import { useDeviceStore } from '@/stores';
import { parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { isCancel } from 'axios';
import destr from 'destr';
import { isString } from 'es-toolkit';
import { NButton, NCard, NFlex, NForm, NFormItem, NFormItemGi, NGrid, NInput, NSwitch, type FormInst, type FormRules } from 'naive-ui';
import { computed, onBeforeUnmount, ref, toRefs, useTemplateRef, watch } from 'vue';

const props = defineProps<{
  ndmDevice: NdmServerResultVO;
  station: Station;
}>();

const deviceStore = useDeviceStore();

const { ndmDevice, station } = toRefs(props);

const localDevice = ref<NdmServerUpdateVO>({ ...ndmDevice.value });
watch(ndmDevice, (newDevice) => {
  localDevice.value = { ...newDevice };
});

const canEditDeviceId = computed(() => {
  const { deviceId } = ndmDevice.value;
  if (!isString(deviceId)) return true;
  if (deviceId.length === 0) return true;
  return false;
});

const validatorAbortController = ref<AbortController>(new AbortController());
const abortController = ref<AbortController>(new AbortController());

const formInst = useTemplateRef<FormInst>('formInst');
const formRules: FormRules = {
  deviceId: {
    trigger: ['input'],
    asyncValidator: async (rule, value: string) => {
      await validateDeviceIdDuplicated({ deviceId: value }).catch((error) => {
        if (isCancel(error)) return;
        throw error;
      });
    },
  },
};

const { mutateAsync: validateDeviceIdDuplicated } = useMutation({
  mutationFn: async (params: { deviceId?: string }) => {
    const { deviceId } = params;
    if (!deviceId) throw new Error('请输入设备ID');

    const deviceIdPattern = /^\d{4}(09|11)\d{4}$/;
    if (!deviceIdPattern.test(deviceId)) throw new Error('设备ID不符合规范');

    // 如果没有修改设备ID，则不做ID唯一性校验
    if (deviceId === ndmDevice.value.deviceId) return;

    validatorAbortController.value.abort();
    validatorAbortController.value = new AbortController();

    const icmpEntities = await icmpEntityByDeviceId(deviceId, {
      stationCode: station.value.code,
      signal: validatorAbortController.value.signal,
    });
    if (icmpEntities.length > 0) throw new Error('该设备ID已存在');
  },
});

const { mutate: updateDevice, isPending } = useMutation({
  mutationFn: async () => {
    await formInst.value?.validate().catch(() => {
      throw new Error('表单校验失败');
    });

    abortController.value.abort();
    abortController.value = new AbortController();

    const deviceType = tryGetDeviceType(localDevice.value.deviceType);
    const stationCode = station.value.code;
    const signal = abortController.value.signal;
    if (deviceType === DEVICE_TYPE_LITERALS.ndmMediaServer) {
      await updateMediaServerApi(localDevice.value, { stationCode, signal });
      return await detailMediaServerApi(`${localDevice.value.id}`, { stationCode, signal });
    } else if (deviceType === DEVICE_TYPE_LITERALS.ndmVideoServer) {
      await updateVideoServerApi(localDevice.value, { stationCode, signal });
      return await detailVideoServerApi(`${localDevice.value.id}`, { stationCode, signal });
    } else {
      throw new Error('不是服务器设备');
    }
  },
  onSuccess: (newDevice) => {
    localDevice.value = { ...newDevice };
    deviceStore.patchDevice(station.value.code, { ...newDevice });
    window.$message.success('更新成功');
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

onBeforeUnmount(() => {
  validatorAbortController.value.abort();
  abortController.value.abort();
});
</script>

<template>
  <NCard hoverable size="small">
    <template #default>
      <NForm size="small" ref="formInst" :model="localDevice" :rules="formRules">
        <NGrid>
          <NFormItemGi span="8" label-placement="left" label="ICMP启用">
            <NSwitch :value="destr(localDevice.icmpEnabled)" @update:value="(enabled: boolean) => (localDevice.icmpEnabled = enabled)" />
          </NFormItemGi>
          <NFormItemGi span="8" label-placement="left" label="SNMP启用">
            <NSwitch :value="destr(localDevice.snmpEnabled)" @update:value="(enabled: boolean) => (localDevice.snmpEnabled = enabled)" />
          </NFormItemGi>
        </NGrid>
        <NFormItem label-placement="left" label="设备ID" path="deviceId">
          <NInput v-model:value="localDevice.deviceId" :disabled="!canEditDeviceId" />
        </NFormItem>
        <NFormItem label-placement="left" label="设备名称">
          <NInput v-model:value="localDevice.name" />
        </NFormItem>
        <NFormItem label-placement="left" label="设备厂商">
          <NInput v-model:value="localDevice.manufacturer" />
        </NFormItem>
        <NFormItem label-placement="left" label="型号">
          <NInput v-model:value="localDevice.model" />
        </NFormItem>
        <NFormItem label-placement="left" label="团体字符串">
          <NInput v-model:value="localDevice.community" />
        </NFormItem>
        <NFormItem label-placement="left" label="设备描述">
          <NInput v-model:value="localDevice.description" />
        </NFormItem>
      </NForm>
    </template>
    <template #action>
      <NFlex justify="end">
        <NButton secondary size="small" :loading="isPending" @click="() => updateDevice()">更新</NButton>
      </NFlex>
    </template>
  </NCard>
</template>

<style scoped lang="scss"></style>
