<script setup lang="ts">
import { getChannelListApi, getRecordCheckApi, reloadAllRecordCheckApi, reloadRecordCheckApi, type NdmNvrResultVO, type RecordItem, type Station } from '@/apis';
import { exportRecordDiagCsv, transformRecordChecks } from '@/helpers';
import { useSettingStore } from '@/stores';
import { parseErrorFeedback } from '@/utils';
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query';
import { isCancel } from 'axios';
import dayjs from 'dayjs';
import { DownloadIcon, RotateCwIcon } from 'lucide-vue-next';
import { NButton, NCard, NFlex, NIcon, NPagination, NPopconfirm, NPopover, NRadioButton, NRadioGroup, NTooltip, useThemeVars } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { computed, onBeforeUnmount, ref, toRefs, watch } from 'vue';

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

const settingStore = useSettingStore();
const { activeRequests } = storeToRefs(settingStore);

const themeVars = useThemeVars();

const queryClient = useQueryClient();

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

const lossInput = ref<number>(0);

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

const NVR_RECORD_CHECK_KEY = 'nvr_record_check_query';

const {
  data: recordChecks,
  isFetching: loading,
  refetch: refetchRecordChecks,
} = useQuery({
  queryKey: computed(() => [NVR_RECORD_CHECK_KEY, ndmDevice.value.id, ndmDevice.value.lastDiagTime]),
  enabled: computed(() => activeRequests.value),
  refetchInterval: 30 * 1000,
  gcTime: 0,
  queryFn: async ({ signal }) => {
    const checks = await getRecordCheckApi(ndmDevice.value, 90, [], { stationCode: station.value.code, signal });
    return checks;
  },
});
watch(activeRequests, (active) => {
  if (!active) {
    queryClient.cancelQueries({ queryKey: [NVR_RECORD_CHECK_KEY] });
  }
});

const recordDiags = computed(() => {
  return transformRecordChecks(recordChecks.value ?? []).filter((recordDiag) => {
    if (lossInput.value === 0) {
      return true;
    } else if (lossInput.value === 1) {
      return recordDiag.lostChunks.length > 0;
    } else if (lossInput.value === 2) {
      return recordDiag.lostChunks.length === 0;
    }
    return false;
  });
});

const { mutate: reloadAllRecordCheck, isPending: reloading } = useMutation({
  mutationFn: async () => {
    abortController.value.abort();
    abortController.value = new AbortController();
    await reloadAllRecordCheckApi(90, { stationCode: station.value.code, signal: abortController.value.signal });
  },
  onSuccess: () => {
    window.$message.success('正在逐步刷新中，请稍后点击刷新按钮查看');
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

const onExportRecordCheck = () => {
  exportRecordDiagCsv(recordDiags.value, station.value.name);
};

const page = ref(1);
const pageSize = ref(10);

const pagedRecordDiags = computed(() => {
  const startIndex = (page.value - 1) * pageSize.value;
  const endIndex = page.value * pageSize.value;
  return recordDiags.value.slice(startIndex, endIndex);
});

const getLostChunkDOMStyle = (lostChunk: RecordItem, duration: RecordItem) => {
  const chunk = dayjs(lostChunk.endTime).diff(dayjs(lostChunk.startTime));
  const offset = dayjs(lostChunk.startTime).diff(dayjs(duration.startTime));
  const total = dayjs(duration.endTime).diff(dayjs(duration.startTime));
  return {
    left: `${(offset / total) * 100}%`,
    width: `${(chunk / total) * 100}%`,
  };
};

const { mutate: reloadRecordCheckByGbId } = useMutation({
  mutationFn: async (params: { gbCode: string }) => {
    abortController.value.abort();
    abortController.value = new AbortController();
    const channelList = await getChannelListApi(ndmDevice.value, { stationCode: station.value.code, signal: abortController.value.signal });
    const channel = channelList.find((channel) => channel.code === params.gbCode);
    if (!channel) throw new Error('通道不存在');
    window.$message.loading('刷新耗时较长, 请不要多次刷新, 并耐心等待...', {
      duration: 1000 * 60 * 60 * 24 * 300,
    });
    const isSuccess = await reloadRecordCheckApi(channel, 90, { stationCode: station.value.code, signal: abortController.value.signal });
    window.$message.destroyAll();
    if (isSuccess) {
      window.$message.success('刷新成功');
    } else {
      window.$message.error('刷新失败');
    }
  },
  onSuccess: () => {
    refetchRecordChecks();
  },
  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 align="center" :size="24">
        <div>录像诊断</div>
        <NPopconfirm @positive-click="() => reloadAllRecordCheck()">
          <template #trigger>
            <NButton secondary size="small" :loading="reloading">更新所有通道录像诊断</NButton>
          </template>
          <template #default>
            <span>确认更新所有通道录像诊断吗？</span>
          </template>
        </NPopconfirm>
      </NFlex>
    </template>
    <template #header-extra>
      <NFlex>
        <NTooltip trigger="hover">
          <template #trigger>
            <NButton size="small" quaternary circle :loading="loading" @click="() => refetchRecordChecks()">
              <template #icon>
                <NIcon :component="RotateCwIcon" />
              </template>
            </NButton>
          </template>
          <template #default>
            <span>刷新数据</span>
          </template>
        </NTooltip>
        <NTooltip trigger="hover">
          <template #trigger>
            <NButton size="small" quaternary circle @click="onExportRecordCheck">
              <template #icon>
                <NIcon :component="DownloadIcon" />
              </template>
            </NButton>
          </template>
          <template #default>
            <span>导出录像诊断</span>
          </template>
        </NTooltip>
      </NFlex>
    </template>
    <template #default>
      <NFlex justify="flex-end" style="margin-bottom: 6px">
        <NRadioGroup size="small" v-model:value="lossInput">
          <NRadioButton label="全部" :value="0" />
          <NRadioButton label="有缺失" :value="1" />
          <NRadioButton label="无缺失" :value="2" />
        </NRadioGroup>
      </NFlex>
      <template v-for="{ gbCode, channelName, recordDuration, lostChunks } in pagedRecordDiags" :key="gbCode">
        <div style="display: flex; justify-content: space-between">
          <div>
            <span>{{ channelName }}</span>
            <span>{{ '\u3000' }}</span>
            <span>{{ recordDuration.startTime }} - {{ recordDuration.endTime }}</span>
          </div>
          <NPopconfirm trigger="click" @positive-click="() => reloadRecordCheckByGbId({ gbCode })">
            <template #trigger>
              <NButton ghost size="tiny" type="info">刷新</NButton>
            </template>
            <template #default>
              <span>是否确认刷新？</span>
            </template>
          </NPopconfirm>
        </div>
        <div style="position: relative; height: 24px; margin: 2px 0" :style="{ backgroundColor: lostChunks.length > 0 ? themeVars.infoColor : themeVars.successColor }">
          <template v-for="{ startTime, endTime } in lostChunks" :key="`${startTime}-${endTime}`">
            <NPopover trigger="hover">
              <template #trigger>
                <div style="position: absolute; height: 100%; cursor: pointer; background-color: #eee" :style="getLostChunkDOMStyle({ startTime, endTime }, recordDuration)" />
              </template>
              <template #default>
                <div>开始时间：{{ dayjs(startTime).format('YYYY-MM-DD HH:mm:ss') }}</div>
                <div>结束时间：{{ dayjs(endTime).format('YYYY-MM-DD HH:mm:ss') }}</div>
              </template>
            </NPopover>
          </template>
        </div>
      </template>
    </template>
    <template #action>
      <NFlex justify="flex-end">
        <NPagination size="small" :page="page" :page-size="pageSize" :page-count="Math.ceil(recordDiags.length / pageSize)" @update:page="(p) => (page = p)">
          <template #prefix>
            <span>{{ `共 ${recordDiags.length} 个通道` }}</span>
          </template>
        </NPagination>
      </NFlex>
    </template>
  </NCard>
</template>

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