<script lang="ts">
// 设备参数配置在系统中的key前缀
const DEVICE_PARAM_PREFIXES = {
  Switch: 'SWITCH_',
  Server: 'SERVER_',
  Decoder: 'DECODER_',
  Nvr: 'NVR_',
  Box: 'BOX_',
  Monitor: 'MONITOR_',
} as const;

type DeviceParamPrefix = (typeof DEVICE_PARAM_PREFIXES)[keyof typeof DEVICE_PARAM_PREFIXES];

// 渲染时的数据结构
interface DeviceParamItem {
  id: string;
  key: string;
  name: string;
  numValue?: number;
  timeValue?: string;
  suffix?: string;
  step?: number;
  min?: number;
  max?: number;
}

// 一些参数值是零点几，一些参数值是好几十，需要根据参数名称中的关键词来做预处理
const parseNumericValue = (name: string, value: string) => {
  let val = parseFloat(value);
  const needMultiply = name.includes('流量') || name.includes('占用率');
  if (needMultiply) val *= 100;
  return val;
};

// 在保存参数时需要反向处理
const deparseNumericValue = (name: string, value: number) => {
  let val = value;
  const needMultiply = name.includes('流量') || name.includes('占用率');
  if (needMultiply) val /= 100;
  return val;
};

const getItemStep = (name: string) => {
  if (name.includes('转速')) return 100;
  return 1;
};

const getItemMax = (name: string) => {
  if (name.includes('转速')) return 50000;
  return 100;
};

const getItemSuffix = (name: string) => {
  const percentLike = name.includes('流量') || name.includes('占用率') || name.includes('湿度');
  const secondLike = name.includes('忽略丢失');
  const currentLike = name.includes('电流');
  const voltageLike = name.includes('电压');
  const temperatureLike = name.includes('温');
  const rpmLike = name.includes('转速');
  if (percentLike) return '%';
  if (secondLike) return '秒';
  if (currentLike) return 'A';
  if (voltageLike) return 'V';
  if (temperatureLike) return '℃';
  if (rpmLike) return '转/分';
  return '';
};

const tabPanes = [
  {
    tab: '交换机阈值',
    name: DEVICE_PARAM_PREFIXES.Switch,
  },
  {
    tab: '服务器阈值',
    name: DEVICE_PARAM_PREFIXES.Server,
  },
  {
    tab: '解码器阈值',
    name: DEVICE_PARAM_PREFIXES.Decoder,
  },
  {
    tab: '录像机阈值',
    name: DEVICE_PARAM_PREFIXES.Nvr,
  },
  {
    tab: '安防箱阈值',
    name: DEVICE_PARAM_PREFIXES.Box,
  },
  {
    tab: '显示器计划',
    name: DEVICE_PARAM_PREFIXES.Monitor,
  },
];
</script>

<script setup lang="ts">
import { pageDefParameterApi, resetMonitorScheduleApi, updateDefParameterApi, type Station } from '@/apis';
import { parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { NFlex, NForm, NFormItemGi, NGrid, NInputNumber, NModal, NSpin, NTabPane, NTabs, NTimePicker } from 'naive-ui';
import { ref, toRefs } from 'vue';

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

const show = defineModel<boolean>('show', { required: true });

const { station } = toRefs(props);

const activeTabName = ref<DeviceParamPrefix>(DEVICE_PARAM_PREFIXES.Switch);

const deviceParams = ref<DeviceParamItem[]>([]);

const { mutate: getDeviceParams, isPending: paramsLoading } = useMutation({
  mutationFn: async (params: { deviceKeyPrefix: string }) => {
    const { deviceKeyPrefix } = params;
    const { records } = await pageDefParameterApi(
      {
        model: {},
        extra: { key_likeRight: deviceKeyPrefix },
        current: 1,
        size: 1000,
        sort: 'id',
        order: 'descending',
      },
      {
        stationCode: station.value?.code,
      },
    );
    return records;
  },
  onSuccess: (records) => {
    deviceParams.value = records.map<DeviceParamItem>((record) => {
      if (record.key?.includes(DEVICE_PARAM_PREFIXES.Monitor)) {
        return {
          id: record.id ?? '',
          key: record.key ?? '',
          name: record.name ?? '',
          timeValue: record.value ?? '',
        };
      }
      return {
        id: record.id ?? '',
        key: record.key ?? '',
        name: record.name ?? '',
        numValue: parseNumericValue(record.name ?? '', record.value ?? '0'),
        suffix: getItemSuffix(record.name ?? ''),
        step: getItemStep(record.name ?? ''),
        min: 0,
        max: getItemMax(record.name ?? ''),
      };
    });
  },
  onError: (error) => {
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

const { mutate: saveDeviceParams } = useMutation({
  mutationFn: async (params: { tabName: string; items: DeviceParamItem[] }) => {
    const { tabName, items } = params;
    for (const item of items) {
      if (tabName.includes(DEVICE_PARAM_PREFIXES.Monitor)) {
        await updateDefParameterApi(
          {
            id: item.id,
            key: item.key,
            name: item.name,
            value: item.timeValue,
          },
          {
            stationCode: station.value?.code,
          },
        );
      } else {
        await updateDefParameterApi(
          {
            id: item.id,
            key: item.key,
            name: item.name,
            value: `${deparseNumericValue(item.name, item.numValue ?? 0)}`,
          },
          {
            stationCode: station.value?.code,
          },
        );
      }
    }
    await resetMonitorScheduleApi({ stationCode: station.value?.code });
  },
  onError: (error) => {
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

const onBeforeTabLeave = (name: string, oldName: string): boolean | Promise<boolean> => {
  saveDeviceParams({ tabName: oldName, items: deviceParams.value });
  getDeviceParams({ deviceKeyPrefix: name });
  return true;
};

const onAfterModalEnter = () => {
  getDeviceParams({ deviceKeyPrefix: activeTabName.value });
};

const onBeforeModalLeave = () => {
  saveDeviceParams({ tabName: activeTabName.value, items: deviceParams.value });
  activeTabName.value = DEVICE_PARAM_PREFIXES.Switch;
  deviceParams.value = [];
};
</script>

<template>
  <NModal
    v-model:show="show"
    preset="card"
    style="width: 800px; height: 600px"
    :title="`${station?.name} - 设备参数配置`"
    :auto-focus="false"
    :close-on-esc="false"
    :mask-closable="false"
    @after-enter="onAfterModalEnter"
    @before-leave="onBeforeModalLeave"
  >
    <NTabs v-model:value="activeTabName" type="card" @before-leave="onBeforeTabLeave">
      <NTabPane v-for="pane in tabPanes" :key="pane.name" :tab="pane.tab" :name="pane.name">
        <NFlex v-if="paramsLoading" :justify="'center'" :align="'center'">
          <NSpin :show="paramsLoading" description="加载设备参数中..." />
        </NFlex>
        <NForm v-else>
          <NGrid cols="1">
            <NFormItemGi v-for="item in deviceParams" :key="item.key" span="1" label-placement="left" :label="item.name">
              <!-- 监视器计划配置渲染时间选择器，其他配置项渲染数字输入框 -->
              <template v-if="activeTabName === DEVICE_PARAM_PREFIXES.Monitor">
                <NTimePicker v-model:formatted-value="item.timeValue" />
              </template>
              <template v-else>
                <NInputNumber v-model:value="item.numValue" :step="item.step" :min="item.min" :max="item.max" style="width: 100%">
                  <template #suffix>
                    <span>{{ item.suffix }}</span>
                  </template>
                </NInputNumber>
              </template>
            </NFormItemGi>
          </NGrid>
        </NForm>
      </NTabPane>
    </NTabs>
  </NModal>
</template>

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