import type { NdmDeviceAlarmLogResultVO, Station, SyncCameraResult } from '@/apis';
import { ALARM_TOPIC, PERMISSION_TOPIC, SYNC_CAMERA_STATUS_TOPIC } from '@/constants';
import { useSettingStore, useStationStore, useUnreadStore, useUserStore } from '@/stores';
import { Client } from '@stomp/stompjs';
import { watchDebounced } from '@vueuse/core';
import destr from 'destr';
import { storeToRefs } from 'pinia';
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { useStationAlarmsMutation, useUserPermissionQuery } from '../query';

const getBrokerUrl = () => {
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
  const { host } = window.location;
  const endpoint = '/ws';
  const brokerURL = `${protocol}//${host}${endpoint}`;
  return brokerURL;
};

export const useStompClient = () => {
  const stationStore = useStationStore();
  const { stations } = storeToRefs(stationStore);

  const unreadStore = useUnreadStore();
  const { unreadLineAlarms } = storeToRefs(unreadStore);

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

  const userStore = useUserStore();
  const { userInfo } = storeToRefs(userStore);

  const { refetch: refetchUserPermissionQuery } = useUserPermissionQuery();
  const { mutate: refreshStationAlarms } = useStationAlarmsMutation();

  const stompClient = ref<Client | null>(null);

  const syncCameraResult = ref<Record<Station['code'], SyncCameraResult>>({});

  onMounted(() => {
    stompClient.value = new Client({
      brokerURL: getBrokerUrl(),
      reconnectDelay: 5000,
      heartbeatIncoming: 10000,
      heartbeatOutgoing: 10000,
      onConnect: () => {
        console.log('Stomp连接成功');
        stompClient.value?.subscribe(ALARM_TOPIC, (message) => {
          const alarm = destr<NdmDeviceAlarmLogResultVO>(message.body);
          const { alarmCategory, stationCode } = alarm;
          if (alarmCategory === '1' && !!stations.value.find((station) => station.code === stationCode)) {
            unreadStore.pushUnreadAlarm(alarm);
          }
        });
        stompClient.value?.subscribe(PERMISSION_TOPIC, (message) => {
          const employeeId = destr<string>(message.body);
          if (userInfo.value?.['employeeId'] !== employeeId) return;
          refetchUserPermissionQuery();
        });
        stompClient.value?.subscribe(SYNC_CAMERA_STATUS_TOPIC, (message) => {
          const { stationCode, startTime, endTime, insertList, updateList, deleteList } = destr<SyncCameraResult>(message.body);
          syncCameraResult.value[stationCode] = { stationCode, startTime, endTime, insertList, updateList, deleteList };
        });
      },
      onDisconnect: () => {
        console.log('Stomp连接断开');
        stompClient.value?.unsubscribe(ALARM_TOPIC);
        stompClient.value?.unsubscribe(PERMISSION_TOPIC);
        stompClient.value?.unsubscribe(SYNC_CAMERA_STATUS_TOPIC);
      },
      onStompError: (frame) => {
        console.log('Stomp错误', frame);
        window.$message.error('Stomp错误');
      },
      onWebSocketError: (event: Event) => {
        console.log('WebSocket错误', event);
        window.$message.error('WebSocket错误');
      },
    });
    if (subscribeMessages.value) {
      stompClient.value.activate();
    }
  });

  onBeforeUnmount(() => {
    stompClient.value?.deactivate();
    stompClient.value = null;
  });

  watch(subscribeMessages, (subscribe) => {
    if (subscribe) {
      stompClient.value?.activate();
    } else {
      stompClient.value?.deactivate();
    }
  });

  // 当有车站的未读报警变化，即新收到告警时，需要同步告警数据，
  // 但告警可能非常频繁，所以需要防抖处理
  const abortControllerMap = ref(new Map<Station['code'], AbortController>());
  watchDebounced(
    () => Object.entries(unreadLineAlarms.value).map(([stationCode, stationAlarms]) => ({ stationCode, count: stationAlarms['unclassified'].length })),
    (newValue, oldValue) => {
      // 关闭消息订阅时，跳过处理
      if (!subscribeMessages.value) return;
      if (newValue.length === 0) return;
      const codes: Station['code'][] = [];
      newValue.forEach(({ stationCode, count }) => {
        const prevState = oldValue.find((stat) => stat.stationCode === stationCode);
        if (!prevState || count !== prevState.count) {
          codes.push(stationCode);
        }
      });
      // console.log('以下车站收到新告警:', codes);
      for (const stationCode of codes) {
        const station = stations.value.find((station) => station.code === stationCode);
        if (!station) continue;
        abortControllerMap.value.get(stationCode)?.abort();
        abortControllerMap.value.set(stationCode, new AbortController());
        refreshStationAlarms({ station, signal: abortControllerMap.value.get(stationCode)?.signal });
      }
    },
    {
      debounce: 2500,
      maxWait: 5000,
    },
  );

  return {
    stompClient,

    syncCameraResult,
    afterCheckSyncCameraResult: () => {
      syncCameraResult.value = {};
    },
  };
};
