<script setup lang="ts">
import { initStationAlarms, initStationDevices, syncCameraApi, syncNvrChannelsApi, type Station } from '@/apis';
import { AlarmDetailModal, DeviceDetailModal, DeviceParamConfigModal, IcmpExportModal, RecordCheckExportModal, StationCard, type StationCardProps } from '@/components';
import { useBatchActions, useLineDevicesQuery } from '@/composables';
import { useAlarmStore, useDeviceStore, usePermissionStore, useSettingStore } from '@/stores';
import { useMutation } from '@tanstack/vue-query';
import { useElementSize } from '@vueuse/core';
import { isCancel } from 'axios';
import { NButton, NButtonGroup, NCheckbox, NFlex, NGrid, NGridItem, NScrollbar } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { computed, ref, useTemplateRef } from 'vue';

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

const permissionStore = usePermissionStore();
const stations = computed(() => permissionStore.stations.VIEW ?? []);

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

const alarmStore = useAlarmStore();
const { lineAlarms } = storeToRefs(alarmStore);

const STATION_CARD_MIN_WIDTH = 230;
const STATION_GRID_PADDING = 8;
const STATION_GRID_GAP = 6;
const STATION_GRID_REF_NAME = 'stationGridRef';
const stationGridRef = useTemplateRef<HTMLDivElement>(STATION_GRID_REF_NAME);
const { width: stationGridWidth } = useElementSize(stationGridRef);
// 计算合适的车站布局列数
const actualStationGridColumns = computed(() => {
  const currentStationCardWidth = (stationGridWidth.value - STATION_GRID_PADDING * 2 - (stationGridCols.value - 1) * STATION_GRID_GAP) / stationGridCols.value;
  // 当卡片宽度大于最小宽度时，说明用户的设置没有问题，直接返回列数
  if (currentStationCardWidth > STATION_CARD_MIN_WIDTH) return stationGridCols.value;
  // 否则，说明用户的设置不合适，需要根据当前布局宽度重新计算列数
  return Math.floor((stationGridWidth.value - STATION_GRID_PADDING * 2 + STATION_GRID_GAP) / STATION_CARD_MIN_WIDTH);
});

const showIcmpExportModal = ref(false);
const showRecordCheckExportModal = ref(false);

const abortController = ref(new AbortController());

const { batchActions, selectedAction, selectableStations, stationSelection, selectionProps, toggleSelectAction, toggleSelectAllStations, confirmAction, cancelAction } = useBatchActions(
  stations,
  abortController,
);

const { refetch: refetchLineDevicesQuery } = useLineDevicesQuery();

const { mutate: syncCamera, isPending: cameraSyncing } = useMutation({
  mutationFn: async () => {
    abortController.value.abort();
    abortController.value = new AbortController();

    const signal = abortController.value.signal;

    const stationCodes = Object.entries(stationSelection.value)
      .filter(([, selected]) => selected)
      .map(([code]) => code);
    const requests = await Promise.allSettled(stationCodes.map((stationCode) => syncCameraApi({ stationCode, signal })));
    return requests.map((result, index) => ({ ...result, stationCode: stationCodes[index] }));
  },
  onSuccess: (requests) => {
    type PromiseRequest = (typeof requests)[number];
    const successRequests: PromiseRequest[] = [];
    const failedRequests: PromiseRequest[] = [];
    const canceledRequests: PromiseRequest[] = [];
    for (const request of requests) {
      if (request.status === 'fulfilled') {
        successRequests.push(request);
      } else if (isCancel(request.reason)) {
        canceledRequests.push(request);
      } else {
        failedRequests.push(request);
      }
    }
    const notices: string[] = [`成功 ${successRequests.length} 个车站`, `失败 ${failedRequests.length} 个车站`];
    if (canceledRequests.length > 0) notices.push(`取消 ${canceledRequests.length} 个车站`);
    window.$notification.info({
      title: '摄像机同步结果',
      content: notices.join('，'),
      duration: 10000,
    });
    if (successRequests.length > 0) {
      // 摄像机同步后，需要重新查询一次设备
      refetchLineDevicesQuery();
    }
    cancelAction();
  },
});

const { mutate: syncNvrChannels, isPending: nvrChannelsSyncing } = useMutation({
  mutationFn: async () => {
    abortController.value.abort();
    abortController.value = new AbortController();

    const signal = abortController.value.signal;

    const stationCodes = Object.entries(stationSelection.value)
      .filter(([, selected]) => selected)
      .map(([code]) => code);
    const requests = await Promise.allSettled(stationCodes.map((stationCode) => syncNvrChannelsApi({ stationCode, signal })));
    return requests.map((result, index) => ({ ...result, stationCode: stationCodes[index] }));
  },
  onSuccess: (requests) => {
    type PromiseRequest = (typeof requests)[number];
    const successRequests: PromiseRequest[] = [];
    const failedRequests: PromiseRequest[] = [];
    const canceledRequests: PromiseRequest[] = [];
    for (const request of requests) {
      if (request.status === 'fulfilled') {
        successRequests.push(request);
      } else if (isCancel(request.reason)) {
        canceledRequests.push(request);
      } else {
        failedRequests.push(request);
      }
    }
    const notices: string[] = [`成功 ${successRequests.length} 个车站`, `失败 ${failedRequests.length} 个车站`];
    if (canceledRequests.length > 0) notices.push(`取消 ${canceledRequests.length} 个车站`);
    window.$notification.info({
      title: '录像机通道同步结果',
      content: notices.join('，'),
      duration: 10000,
    });
    cancelAction();
  },
});

const confirming = computed(() => cameraSyncing.value || nvrChannelsSyncing.value);

const onClickConfirmAction = () => {
  confirmAction({
    'export-icmp': () => {
      showIcmpExportModal.value = true;
    },
    'export-record': () => {
      showRecordCheckExportModal.value = true;
    },
    'sync-camera': () => {
      syncCamera();
    },
    'sync-nvr': () => {
      syncNvrChannels();
    },
  });
};

// 车站卡片的事件
const modalStation = ref<Station>();
const showDeviceParamConfigModal = ref(false);
const showDeviceDetailModal = ref(false);
const showAlarmDetailModal = ref(false);

const onClickConfig: StationCardProps['onClickConfig'] = (station) => {
  modalStation.value = station;
  showDeviceParamConfigModal.value = true;
};

const onClickDetail: StationCardProps['onClickDetail'] = (type, station) => {
  modalStation.value = station;
  if (type === 'device') {
    showDeviceDetailModal.value = true;
  }
  if (type === 'alarm') {
    showAlarmDetailModal.value = true;
  }
};
</script>

<template>
  <NScrollbar content-style="padding-right: 8px" style="width: 100%; height: 100%">
    <!-- 工具栏 -->
    <NFlex align="center" :style="{ padding: `${STATION_GRID_PADDING}px ${STATION_GRID_PADDING}px 0 ${STATION_GRID_PADDING}px` }">
      <NButtonGroup>
        <template v-for="batchAction in batchActions" :key="batchAction.key">
          <NButton :secondary="!batchAction.active" :focusable="false" @click="() => toggleSelectAction(batchAction)">{{ batchAction.label }}</NButton>
        </template>
      </NButtonGroup>
      <template v-if="selectedAction">
        <NCheckbox label="全选" :disabled="selectionProps.disabled" :checked="selectionProps.checked" :indeterminate="selectionProps.indeterminate" @update:checked="toggleSelectAllStations" />
        <NButton tertiary size="small" type="primary" :focusable="false" :loading="confirming" @click="onClickConfirmAction">确定</NButton>
        <NButton tertiary size="small" type="tertiary" :focusable="false" @click="cancelAction">取消</NButton>
      </template>
    </NFlex>

    <!-- 车站 -->
    <div :ref="STATION_GRID_REF_NAME">
      <NGrid :cols="actualStationGridColumns" :x-gap="STATION_GRID_GAP" :y-gap="STATION_GRID_GAP" :style="{ padding: `${STATION_GRID_PADDING}px` }">
        <NGridItem v-for="station in stations" :key="station.code">
          <StationCard
            :station="station"
            :devices="lineDevices[station.code] ?? initStationDevices()"
            :alarms="lineAlarms[station.code] ?? initStationAlarms()"
            :selectable="!!selectableStations.find((selectable) => selectable.code === station.code)"
            v-model:selected="stationSelection[station.code]"
            @click-detail="onClickDetail"
            @click-config="onClickConfig"
          />
        </NGridItem>
      </NGrid>
    </div>
  </NScrollbar>

  <IcmpExportModal v-model:show="showIcmpExportModal" :stations="stations.filter((station) => stationSelection[station.code])" @after-leave="cancelAction" />
  <RecordCheckExportModal v-model:show="showRecordCheckExportModal" :stations="stations.filter((station) => stationSelection[station.code])" @after-leave="cancelAction" />

  <DeviceParamConfigModal v-model:show="showDeviceParamConfigModal" :station="modalStation" />
  <DeviceDetailModal v-model:show="showDeviceDetailModal" :station="modalStation" />
  <AlarmDetailModal v-model:show="showAlarmDetailModal" :station="modalStation" />
</template>

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