<script setup lang="ts">
import { detailDeviceApi, probeDeviceApi, type LinkDescription, type NdmDeviceResultVO, type Station } from '@/apis';
import { SELECT_DEVICE_FN_INJECTION_KEY } from '@/constants';
import { DEVICE_TYPE_LITERALS, DEVICE_TYPE_NAMES, 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 { LinkIcon, RotateCwIcon } from 'lucide-vue-next';
import { NButton, NCard, NFlex, NIcon, NTag, NTooltip } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { computed, inject, onBeforeUnmount, ref, toRefs } from 'vue';

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

defineSlots<{
  'append-info': () => any;
}>();

const deviceStore = useDeviceStore();
const { lineDevices } = storeToRefs(deviceStore);

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

const type = computed(() => {
  const deviceType = tryGetDeviceType(ndmDevice.value.deviceType);
  if (!deviceType) return '-';
  return DEVICE_TYPE_NAMES[deviceType];
});
const name = computed(() => ndmDevice.value.name ?? '-');
const status = computed(() => ndmDevice.value.deviceStatus);
const ipAddr = computed(() => ndmDevice.value.ipAddress ?? '-');
const gbCode = computed(() => Reflect.get(ndmDevice.value, 'gbCode') as string | undefined);

const linkDescription = computed(() => {
  const result = destr<any>(ndmDevice.value.linkDescription);
  if (!result) return null;
  if (typeof result !== 'object') return null;
  return result as LinkDescription;
});

const upperDevices = computed(() => {
  const devices: NdmDeviceResultVO[] = [];
  if (!linkDescription.value) return devices;
  if (!linkDescription.value.upstream) return devices;
  linkDescription.value.upstream.forEach((deviceStoreIndex) => {
    const { stationCode, deviceType, deviceDbId } = deviceStoreIndex;
    const stationDevices = lineDevices.value[stationCode];
    if (!stationDevices) return;
    const classified = stationDevices[deviceType];
    const device = classified.find((device) => device.id === deviceDbId);
    if (device) devices.push(device);
  });
  return devices.sort((aDevice, bDevice) => {
    // 按在DEVICE_TYPE_LITERALS中的顺序排序
    const aDeviceType = tryGetDeviceType(aDevice.deviceType);
    const bDeviceType = tryGetDeviceType(bDevice.deviceType);
    if (!aDeviceType || !bDeviceType) return 0;
    const deviceTypes = Object.values(DEVICE_TYPE_LITERALS);
    return deviceTypes.indexOf(aDeviceType) - deviceTypes.indexOf(bDeviceType);
  });
});

// 获取从父组件注入的 `selectDevice` 函数
const selectDeviceFn = inject(SELECT_DEVICE_FN_INJECTION_KEY);
// 跳转到上游设备
const navigateToUpperDevice = (upperDevice: NdmDeviceResultVO) => {
  if (!!selectDeviceFn && !!selectDeviceFn.value) {
    selectDeviceFn.value(upperDevice, station.value.code);
  }
};

const canOpenMgmtPage = computed(() => {
  return Object.keys(ndmDevice.value).includes('manageUrl');
});
const canProbe = computed(() => !!ndmDevice.value.snmpEnabled);

const onClickOpenMgmtPage = () => {
  if (canOpenMgmtPage.value) {
    let target = '';
    const manageUrl = ndmDevice.value.manageUrl;
    const ipAddress = ndmDevice.value.ipAddress;
    if (manageUrl) {
      target = manageUrl;
    } else if (ipAddress) {
      target = `http://${ipAddress}`;
    }
    if (target) {
      window.open(target, '_blank');
      return;
    }
    window.$message.warning('未找到设备IP地址');
  }
};

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

const { mutate: probeDevice, isPending: probing } = useMutation({
  mutationFn: async () => {
    abortController.value.abort();
    abortController.value = new AbortController();
    await probeDeviceApi(ndmDevice.value, { stationCode: station.value.code, signal: abortController.value.signal });
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

const { mutate: detailDevice, isPending: loading } = useMutation({
  mutationFn: async () => {
    abortController.value.abort();
    abortController.value = new AbortController();
    return await detailDeviceApi(ndmDevice.value, { stationCode: station.value.code, signal: abortController.value.signal });
  },
  onSuccess: (device) => {
    if (device) {
      useDeviceStore().patchDevice(station.value.code, device);
    }
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

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

<template>
  <NCard hoverable size="small">
    <template #header>
      <NFlex vertical>
        <NFlex align="center">
          <NTag v-if="status === '10'" size="small" type="success">在线</NTag>
          <NTag v-else-if="status === '20'" size="small" type="error">离线</NTag>
          <NTag v-else size="small" type="warning">-</NTag>
          <div>{{ name }}</div>
          <NButton v-if="canOpenMgmtPage" ghost size="tiny" type="default" :focusable="false" @click="onClickOpenMgmtPage">管理</NButton>
          <div style="margin-left: auto">
            <NTooltip v-if="canProbe" trigger="hover">
              <template #trigger>
                <NButton size="small" quaternary circle :loading="probing" @click="() => probeDevice()">
                  <template #icon>
                    <NIcon :component="LinkIcon" />
                  </template>
                </NButton>
              </template>
              <template #default>
                <span>请求最新诊断</span>
              </template>
            </NTooltip>
            <NTooltip trigger="hover">
              <template #trigger>
                <NButton size="small" quaternary circle :loading="loading" @click="() => detailDevice()">
                  <template #icon>
                    <NIcon :component="RotateCwIcon" />
                  </template>
                </NButton>
              </template>
              <template #default>
                <span>刷新设备</span>
              </template>
            </NTooltip>
          </div>
        </NFlex>
        <div v-if="upperDevices.length > 0" style="font-size: 0.85rem">
          <span>上游设备：</span>
          <template v-for="(device, index) in upperDevices" :key="index">
            <span style="text-decoration: underline; cursor: pointer" @click="() => navigateToUpperDevice(device)">{{ device.name }}</span>
            <span v-if="index < upperDevices.length - 1">、</span>
          </template>
        </div>
      </NFlex>
    </template>
    <template #default>
      <div style="font-size: small; color: #666">
        <div>
          <span>设备类型：</span>
          <span>{{ type }}</span>
        </div>
        <div>
          <span>IP地址：</span>
          <span>{{ ipAddr }}</span>
        </div>
        <div v-if="gbCode">
          <span>国标编码：</span>
          <span>{{ gbCode }}</span>
        </div>
        <div v-if="!!ndmDevice.description">
          <span>设备描述：</span>
          <span>{{ ndmDevice.description }}</span>
        </div>
        <div v-if="ndmDevice.snmpEnabled">
          <span>上次诊断时间：</span>
          <span>{{ ndmDevice.lastDiagTime ?? '-' }}</span>
        </div>
      </div>
    </template>
    <template #footer>
      <slot name="append-info"></slot>
    </template>
  </NCard>
</template>

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