import { deleteDeviceApi, exportDeviceApi, importDeviceApi, type ImportMsg, type NdmDeviceLinkDescription, type NdmDevicePageQuery, type PageParams, type Station } from '@/apis';
import { useStationDevicesMutation } from '@/composables';
import { DEVICE_TYPE_NAMES, type DeviceType } from '@/enums';
import { useDeviceStore, useStationStore } from '@/stores';
import { downloadByData, parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { isCancel } from 'axios';
import dayjs from 'dayjs';
import destr from 'destr';
import { storeToRefs } from 'pinia';
import { h, onBeforeUnmount } from 'vue';

export const useDeviceManagement = () => {
  const stationStore = useStationStore();
  const { stations } = storeToRefs(stationStore);
  const deviceStore = useDeviceStore();
  const { lineDevices } = storeToRefs(deviceStore);

  const { mutate: refreshStationDevices } = useStationDevicesMutation();

  // 导出设备
  const { mutate: exportDevice } = useMutation({
    mutationFn: async (params: { deviceType: DeviceType; stationCode: Station['code']; signal?: AbortSignal }) => {
      const { deviceType, stationCode, signal } = params;
      const deviceTypeName = DEVICE_TYPE_NAMES[deviceType];
      const stationDevices = lineDevices.value[stationCode];
      if (!stationDevices) throw new Error(`该车站没有${deviceTypeName}`);
      const devices = stationDevices[deviceType];

      const pageQuery: PageParams<NdmDevicePageQuery> = {
        model: {},
        extra: {},
        current: 1,
        size: devices.length,
        sort: 'id',
        order: 'descending',
      };

      window.$loadingBar.start();

      const data = await exportDeviceApi(deviceType, pageQuery, { stationCode, signal });
      return data;
    },
    onSuccess: (data, { deviceType, stationCode }) => {
      window.$loadingBar.finish();
      const time = dayjs().format('YYYY-MM-DD_HH-mm-ss');
      const stationName = stations.value.find((station) => station.code === stationCode)?.name ?? '';
      const deviceTypeName = DEVICE_TYPE_NAMES[deviceType];
      downloadByData(data, `${stationName}_${deviceTypeName}列表_${time}.xlsx`);
    },
    onError: (error) => {
      window.$loadingBar.error();
      if (isCancel(error)) return;
      console.error(error);
      const errorFeedback = parseErrorFeedback(error);
      window.$message.error(errorFeedback);
    },
  });

  // 下载设备导入模板
  // FIXME: 采用导出空列表的方案，但是后端生成的xlsx中会多一行空行，如果直接再导入该文件就会多导入一个空设备
  const { mutate: exportDeviceTemplate } = useMutation({
    mutationFn: async (params: { deviceType: DeviceType; stationCode: Station['code']; signal?: AbortSignal }) => {
      const { deviceType, stationCode, signal } = params;

      const pageQuery: PageParams<NdmDevicePageQuery> = {
        model: {},
        extra: {},
        current: 1,
        size: 0,
        sort: 'id',
        order: 'descending',
      };

      window.$loadingBar.start();

      const data = await exportDeviceApi(deviceType, pageQuery, { stationCode, signal });
      return data;
    },
    onSuccess: (data, { deviceType, stationCode }) => {
      window.$loadingBar.finish();
      const time = dayjs().format('YYYY-MM-DD_HH-mm-ss');
      const stationName = stations.value.find((station) => station.code === stationCode)?.name ?? '';
      const deviceTypeName = DEVICE_TYPE_NAMES[deviceType];
      downloadByData(data, `${stationName}_${deviceTypeName}导入模板_${time}.xlsx`);
    },
    onError: (error) => {
      window.$loadingBar.error();
      if (isCancel(error)) return;
      console.error(error);
      const errorFeedback = parseErrorFeedback(error);
      window.$message.error(errorFeedback);
    },
  });

  // 导入设备
  const { mutate: importDevice } = useMutation({
    mutationFn: async (params: { deviceType: DeviceType; stationCode: Station['code']; signal?: AbortSignal }) => {
      const { deviceType, stationCode, signal } = params;
      const data = await new Promise<ImportMsg>((resolve) => {
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = '.xlsx';
        fileInput.click();
        fileInput.onchange = async () => {
          const file = fileInput.files?.[0];
          // console.log(file);
          if (!file) {
            window.$message.error('导入失败');
            return;
          }

          window.$loadingBar.start();

          const data = await importDeviceApi(deviceType, file, { stationCode, signal });
          resolve(data);
        };
      });
      return data;
    },
    onSuccess: (data, { stationCode, signal }) => {
      window.$loadingBar.finish();
      window.$dialog.success({
        title: '导入成功',
        content: () => {
          return h('div', {}, [
            h('p', {}, `新增数据：${data.insertNum}条`),
            h('p', {}, `更新数据：${data.updateNum}条`),
            h('p', {}, `不变数据：${data.unchangedNum}条`),
            h('p', {}, `错误数据：${data.wrongNum}条`),
            data.wrongLines.map((line) => h('p', { style: { 'margin-left': '8px' } }, `第${line.rowNum}行：${line.msg}`)),
          ]);
        },
      });
      const station = stations.value.find((station) => station.code === stationCode);
      if (station) {
        refreshStationDevices({ station, signal });
      }
    },
    onError: (error) => {
      window.$loadingBar.error();
      if (isCancel(error)) return;
      console.error(error);
      const errorFeedback = parseErrorFeedback(error);
      window.$message.error(errorFeedback);
    },
  });

  // 删除设备
  const { mutate: deleteDevice } = useMutation({
    mutationFn: async (params: { id: string; deviceType: DeviceType; stationCode: Station['code']; signal?: AbortSignal }) => {
      const { id, deviceType, stationCode, signal } = params;

      window.$loadingBar.start();

      // 检查要删除的设备是否存在关联设备
      const stationDevices = lineDevices.value[stationCode];
      if (!!stationDevices) {
        const classified = stationDevices[deviceType];
        if (!!classified) {
          const device = classified.find((device) => device.id === id);
          if (!!device) {
            const maybeLinkDescription = destr<any>(device.linkDescription);
            if (!!maybeLinkDescription && typeof maybeLinkDescription === 'object') {
              const linkDescription = maybeLinkDescription as NdmDeviceLinkDescription;
              // 只要有上游或下游设备，就不能删除
              const { upstream } = linkDescription;
              if (!!upstream && upstream.length > 0) {
                throw new Error('该设备存在关联的上游设备，无法删除');
              }
              if ('downstream' in linkDescription) {
                const { downstream } = linkDescription;
                if (!!downstream && Object.keys(downstream).length > 0) {
                  throw new Error('该设备存在关联的下游设备，无法删除');
                }
              }
            }
          }
        }
      }

      return await deleteDeviceApi(deviceType, id, { stationCode, signal });
    },
    onSuccess: (_, { stationCode, signal }) => {
      window.$loadingBar.finish();
      window.$message.success('删除成功');
      const station = stations.value.find((station) => station.code === stationCode);
      if (station) {
        refreshStationDevices({ station, signal });
      }
    },
    onError: (error) => {
      window.$loadingBar.error();
      if (isCancel(error)) return;
      console.error(error);
      const errorFeedback = parseErrorFeedback(error);
      window.$message.error(errorFeedback);
    },
  });

  onBeforeUnmount(() => {
    window.$loadingBar.finish();
  });

  return {
    exportDevice,
    exportDeviceTemplate,
    importDevice,
    deleteDevice,
  };
};

export type UseDeviceManagementReturn = ReturnType<typeof useDeviceManagement>;
