<script setup lang="ts">
import { pageIcmpLogApi, type NdmDeviceResultVO, type NdmIcmpLogResultVO, type PageParams, type PageResult, type Station } from '@/apis';
import { formatDuration, parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { isCancel } from 'axios';
import dayjs from 'dayjs';
import { NCard, NFlex, NPagination, NScrollbar, NSpin, NTimeline, NTimelineItem, type PaginationProps, type TimelineItemProps } from 'naive-ui';
import { computed, h, onBeforeUnmount, reactive, ref, toRefs, watch } from 'vue';

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

const range = defineModel<[number, number]>('range');
const loading = defineModel<boolean>('loading', { default: false });

const emit = defineEmits<{
  exposeQueryFn: [queryFn: () => void];
}>();

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

const icmpLogs = ref<NdmIcmpLogResultVO[]>([]);
const lastItem = ref<NdmIcmpLogResultVO>();

const DEFAULT_PAGE_SIZE = 6;
const pagination = reactive<PaginationProps>({
  size: 'small',
  showSizePicker: true,
  page: 1,
  pageSize: DEFAULT_PAGE_SIZE,
  pageSizes: [6, 10, 20, 50, 80, 100],
  itemCount: 0,
  prefix: ({ itemCount }) => {
    return h('div', {}, { default: () => `共${itemCount}条` });
  },
  onUpdatePage: (page: number) => {
    pagination.page = page;
    getIcmpLogs();
  },
  onUpdatePageSize: (pageSize: number) => {
    pagination.pageSize = pageSize;
    pagination.page = 1;
    getIcmpLogs();
  },
});

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

const { mutate: getIcmpLogs, isPending } = useMutation({
  mutationFn: async () => {
    if (!range.value) throw new Error('请选择时间范围');
    abortController.value?.abort();
    abortController.value = new AbortController();
    const deviceId = ndmDevice.value.id;
    if (!deviceId) throw new Error('该设备没有ID');
    const createdTime_precisest = dayjs(range.value[0]).format('YYYY-MM-DD HH:mm:ss');
    const createdTime_preciseed = dayjs(range.value[1]).format('YYYY-MM-DD HH:mm:ss');
    const restParams: Omit<PageParams<{ id: string }>, 'model' | 'extra'> = {
      current: pagination.page ?? 1,
      size: pagination.pageSize ?? DEFAULT_PAGE_SIZE,
      sort: 'id',
      order: 'descending',
    };
    const currPageResult = await pageIcmpLogApi(
      {
        model: { deviceId: deviceId },
        extra: { createdTime_precisest, createdTime_preciseed },
        ...restParams,
      },
      {
        stationCode: station.value.code,
        signal: abortController.value.signal,
      },
    );
    let lastPageResult: PageResult<NdmIcmpLogResultVO> | undefined = undefined;
    if ((pagination.page ?? 1) > 1) {
      lastPageResult = await pageIcmpLogApi(
        {
          model: { deviceId: deviceId },
          extra: { createdTime_precisest, createdTime_preciseed },
          ...restParams,
          current: (pagination.page ?? 1) - 1,
        },
        {
          stationCode: station.value.code,
          signal: abortController.value.signal,
        },
      );
    }
    return { currPageResult, lastPageResult };
  },
  onSuccess: ({ currPageResult: { records, size, total }, lastPageResult }) => {
    pagination.pageSize = parseInt(size);
    pagination.itemCount = parseInt(total);
    icmpLogs.value = records;
    lastItem.value = lastPageResult?.records.at(-1);
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

emit('exposeQueryFn', () => {
  pagination.page = 1;
  pagination.pageSize = DEFAULT_PAGE_SIZE;
  getIcmpLogs();
});

watch(isPending, (pending) => {
  loading.value = pending;
});

const timelineItems = computed<TimelineItemProps[]>(() => {
  const items: TimelineItemProps[] = [];
  if (icmpLogs.value.length === 0 && !loading.value) {
    const { deviceStatus } = ndmDevice.value;
    const type: TimelineItemProps['type'] = deviceStatus === '10' ? 'success' : deviceStatus === '20' ? 'error' : 'warning';
    const title = deviceStatus === '10' ? '在线' : deviceStatus === '20' ? '离线' : '未知';
    const content = '至今' + (deviceStatus === '10' ? '在线' : deviceStatus === '20' ? '离线' : '未知');
    items.push({ type, title, content });
    return items;
  }
  let lastIcmpLog = lastItem.value;
  for (const icmpLog of icmpLogs.value) {
    const { deviceStatus, createdTime } = icmpLog;
    if (!createdTime) continue;
    const type: TimelineItemProps['type'] = deviceStatus === '10' ? 'success' : deviceStatus === '20' ? 'error' : 'warning';
    const title = deviceStatus === '10' ? '在线' : deviceStatus === '20' ? '离线' : '未知';
    const content = `持续时长：${lastIcmpLog ? formatDuration(createdTime, lastIcmpLog.createdTime) : '至今'}`;
    const time = createdTime;
    items.push({ type, title, content, time });
    lastIcmpLog = icmpLog;
  }
  return items;
});

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

<template>
  <NCard hoverable size="small" :content-style="{ 'max-height': '500px' }">
    <template #header>
      <span>设备状态记录</span>
    </template>
    <template #default>
      <NSpin v-if="loading" style="width: 100%; height: 100%; display: flex"></NSpin>
      <div v-else-if="timelineItems.length === 0" style="width: 100%; display: flex; color: #666">
        <div style="margin: auto">暂无记录</div>
      </div>
      <NTimeline v-else-if="timelineItems.length <= DEFAULT_PAGE_SIZE">
        <NTimelineItem v-for="{ type, title, content, time } in timelineItems" :key="time" :type="type" :title="title" :content="content" :time="time"></NTimelineItem>
      </NTimeline>
      <NScrollbar v-else x-scrollable>
        <NTimeline>
          <NTimelineItem v-for="{ type, title, content, time } in timelineItems" :key="time" :type="type" :title="title" :content="content" :time="time"></NTimelineItem>
        </NTimeline>
      </NScrollbar>
    </template>
    <template #footer>
      <NFlex justify="end">
        <NPagination
          v-model:page="pagination.page"
          v-model:page-size="pagination.pageSize"
          :page-sizes="pagination.pageSizes"
          :item-count="pagination.itemCount"
          size="small"
          show-size-picker
          @update-page="pagination.onUpdatePage"
          @update:page-size="pagination.onUpdatePageSize"
        />
      </NFlex>
    </template>
  </NCard>
</template>

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