<script setup lang="ts">
import { onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useInfiniteScroll } from '@vueuse/core';
import dayjs from 'dayjs';

import SvgIcon from '@/components/SvgIcon.vue';
import { useRequest } from '@/hooks/request';
import { getDevWorkRealTimeData, getDevWorkTypeCount, queryDevicesList } from '@/api';
import { getFixedNum } from '@/utils';
import { DeviceStatusQuery } from '@/constants';
import { DevParamChillerUnit, DevParamCtrlCabinet } from '@/constants/device-params';

import { deviceCardData, DeviceType } from './device-card';
import DeviceWorkParams from './DeviceWorkParams.vue';
import DevWorkParamData from './DevWorkParamData.vue';

import type { DevGroupTabCompProps, DevicesListItem, DeviceTypeCount, PageParams } from '@/types';

const props = defineProps<DevGroupTabCompProps>();

const router = useRouter();
const route = useRoute();
const { isLoading, handleRequest } = useRequest();
const deviceTypes = ref<DeviceTypeCount[]>([]);
const activeDeviceId = ref<number>();
const activeDeviceType = ref<DeviceType>(DeviceType.空);
const activeDeviceStatus = ref<DeviceStatusQuery>(DeviceStatusQuery.All);

const deviceTypeOrder = [
  DeviceType.冷水主机,
  DeviceType.控制柜,
  DeviceType.冷却塔,
  DeviceType.冷却泵,
  DeviceType.冷冻泵,
];

onMounted(() => {
  handleRequest(async () => {
    deviceTypes.value = await getDevWorkTypeCount(props.deviceGroupId, deviceTypeOrder);

    deviceTypes.value.sort((a, b) => {
      const indexA = deviceTypeOrder.indexOf(a.deviceType);
      const indexB = deviceTypeOrder.indexOf(b.deviceType);

      // 如果某个设备类型不在指定顺序中，将其放在末尾
      if (indexA === -1) return 1;
      if (indexB === -1) return -1;

      return indexA - indexB;
    });

    if (deviceTypes.value.length) {
      activeDeviceId.value = route.query.deviceId ? Number(route.query.deviceId) : undefined;

      if (route.query.deviceType) {
        const deviceType = Number(route.query.deviceType);
        const isDeviceTypeExisted = deviceTypes.value.find((item) => item.deviceType === deviceType);

        if (isDeviceTypeExisted) {
          activeDeviceType.value = deviceType;

          router.replace({
            path: route.path,
            query: {
              tab: 'deviceWorkStatus',
              r: route.query.r,
            },
          });
        }
      } else {
        activeDeviceType.value = deviceTypes.value[0].deviceType;
      }

      getDeviceList();
    }
  });
});

/**
 * 设备实时数据映射对象
 * - 以设备 id 作为 key
 * - 时间与设备参数的值构成的对象作为 value
 */
type DeviceRTDMap = Record<
  number,
  {
    [key: string]: number | string | undefined;
    time?: string;
    flushTime?: string;
  }
>;

const deviceList = ref<DevicesListItem[]>([]);
const deviceTotal = ref(0);
const devRTDUpdateTime = ref('');
const deviceRealTimeData = ref<DeviceRTDMap>({});
const pageParams = ref<PageParams>({
  pageIndex: 1,
  pageSize: 12,
  pageSorts: [
    {
      column: 'id',
      asc: true,
    },
  ],
});

const deviceListEl = useTemplateRef('deviceListEl');

useInfiniteScroll(
  deviceListEl,
  () => {
    getDeviceList();
  },
  {
    distance: 10,
    canLoadMore: () => {
      if (pageParams.value.pageIndex === 1 || isLoading.value) {
        return false;
      }

      return deviceList.value.length < deviceTotal.value;
    },
  },
);

const getDeviceList = () => {
  handleRequest(async () => {
    let status = null;

    if (activeDeviceStatus.value === DeviceStatusQuery.Offline) {
      status = 0;
    } else if (activeDeviceStatus.value === DeviceStatusQuery.Online) {
      status = 1;
    }

    const { records, total } = await queryDevicesList({
      ...pageParams.value,
      deviceType: activeDeviceType.value,
      groupId: props.deviceGroupId,
      status,
    });

    deviceList.value.push(...records);
    deviceTotal.value = total;
    pageParams.value.pageIndex++;

    getRealTimeData();
  });
};

let devRTDTimer: number | undefined;

onUnmounted(() => {
  clearTimeout(devRTDTimer);
});

const getRealTimeData = () => {
  clearTimeout(devRTDTimer);

  handleRequest(async () => {
    if (!deviceList.value.length) {
      return;
    }

    const deviceIds = deviceList.value.map((item) => item.id);
    const deviceParamCode = deviceCardData[activeDeviceType.value]?.paramCodes || [];
    devRTDUpdateTime.value = dayjs().format('YYYY-MM-DD HH:mm:ss');

    const data = await getDevWorkRealTimeData({
      deviceType: activeDeviceType.value,
      deviceIds,
      deviceParamCode,
      endTime: devRTDUpdateTime.value,
    });

    data.forEach((item) => {
      const { deviceId, deviceParamMapList, ...extraParams } = item;
      deviceRealTimeData.value[deviceId] = {};

      deviceParamMapList.forEach((paramItem) => {
        Object.assign(deviceRealTimeData.value[deviceId], paramItem);
      });

      if (extraParams.flushTime === 'null') {
        extraParams.flushTime = null;
      }

      Object.assign(deviceRealTimeData.value[deviceId], extraParams);
    });
  });

  devRTDTimer = window.setTimeout(getRealTimeData, 3 * 60 * 1000);
};

const handleTabClick = () => {
  deviceList.value = [];
  deviceTotal.value = 0;
  deviceRealTimeData.value = {};

  setTimeout(() => {
    pageParams.value.pageIndex = 1;
    getDeviceList();
  }, 0);
};

const deviceWorkParamsRef = useTemplateRef('deviceWorkParams');

const currentDevId = ref<number>(0);

const viewDevParam = (id: number, e: MouseEvent) => {
  e.stopPropagation();
  currentDevId.value = id;
  deviceWorkParamsRef.value?.showView();
};

const devWorkParamDataRef = useTemplateRef('devWorkParamData');

const currentDevParamCodes = ref<string[]>([]);

const viewHistoryData = (paramCode: string) => {
  currentDevParamCodes.value = [paramCode];
  devWorkParamDataRef.value?.showView();
};

/**
 * 使用事件委托处理设置了参数编码属性 data-param-code 的元素的点击事件，用来查看该参数的历史数据
 */
const handleDevCardClick = (devId: number, e: Event) => {
  const target = e.target as HTMLElement;
  const { paramCode } = target.dataset;

  if (paramCode) {
    currentDevId.value = devId;
    viewHistoryData(paramCode);
  } else {
    router.push({
      path: `/device-manage/device-list/equipment-details/${devId}`,
      query: {
        from: 'deviceWorkStatus',
        groupId: props.deviceGroupId,
        deviceType: activeDeviceType.value,
      },
    });
  }
};
</script>

<template>
  <div class="device-work-container">
    <div class="device-work-header">
      <ATabs
        class="button-tabs-card device-type-tab"
        v-model:active-key="activeDeviceType"
        type="card"
        @tab-click="handleTabClick"
      >
        <ATabPane v-for="item in deviceTypes" :key="item.deviceType" :tab="`${item.deviceTypeName}(${item.count})`" />
      </ATabs>
      <ATabs class="device-status-tab" v-model:active-key="activeDeviceStatus" @tab-click="handleTabClick">
        <ATabPane :key="DeviceStatusQuery.All" :tab="$t('common.entire')" />
        <ATabPane :key="DeviceStatusQuery.Online" :tab="$t('common.online')" />
        <ATabPane :key="DeviceStatusQuery.Offline" :tab="$t('common.offline')" />
      </ATabs>
    </div>
    <div ref="deviceListEl" class="device-card-list">
      <AEmpty class="device-card-empty" v-show="!deviceList.length" />
      <ARow :gutter="[22, 24]">
        <ACol v-for="item in deviceList" :key="item.id" :xs="24" :sm="24" :md="24" :lg="24" :xl="12" :xxl="8">
          <div class="device-card-container" @click="handleDevCardClick(item.id, $event)">
            <div class="device-card-header">
              <span
                :class="[
                  'status-dot',
                  {
                    'status-dot-green': item.status === 1,
                  },
                ]"
              ></span>
              <div class="ellipsis-text device-card-header-title">{{ item.deviceName }}</div>
              <div
                v-if="
                  activeDeviceType === DeviceType.控制柜 &&
                  deviceRealTimeData[item.id]?.[DevParamCtrlCabinet.系统控制模式设定]
                "
                class="ctrl-cabinet-mode"
              >
                {{ deviceRealTimeData[item.id][DevParamCtrlCabinet.系统控制模式设定] }}
              </div>
              <template
                v-if="
                  item.enableCopSet &&
                  activeDeviceType === DeviceType.冷水主机 &&
                  deviceRealTimeData[item.id]?.[DevParamChillerUnit.COP] !== undefined
                "
              >
                <div class="device-cop-value" :data-param-code="DevParamChillerUnit.COP">
                  {{ getFixedNum(deviceRealTimeData[item.id][DevParamChillerUnit.COP]) }}
                </div>
                <!-- <div class="device-cop-level">中</div> -->
              </template>
              <span class="device-card-header-time">{{ deviceRealTimeData[item.id]?.flushTime }}</span>
              <SvgIcon class="device-card-header-button" name="adjustment" @click="viewDevParam(item.id, $event)" />
            </div>
            <component
              :is="deviceCardData[activeDeviceType]?.component"
              :real-time-data="deviceRealTimeData[item.id]"
              :device-detail="JSON.parse(item.deviceDetail || '{}')"
              :enable-cop-set="item.enableCopSet"
            />
          </div>
        </ACol>
      </ARow>
      <ASpin v-if="isLoading" class="center-loading" :spinning="true" />
    </div>
    <DeviceWorkParams ref="deviceWorkParams" :dev-id="currentDevId" @view-history-data="viewHistoryData" />
    <DevWorkParamData ref="devWorkParamData" :dev-id="currentDevId" :param-codes="currentDevParamCodes" />
  </div>
</template>

<style lang="scss" scoped>
.device-work-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.device-work-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.device-type-tab {
  width: calc(100% - 200px);
}

:deep(.device-status-tab) {
  font-weight: 500;
  line-height: 22px;

  &.ant-tabs-top > .ant-tabs-nav {
    .ant-tabs-tab {
      padding: 5px 0;

      + .ant-tabs-tab {
        margin-left: 24px;
      }
    }

    &::before {
      border: none;
    }
  }
}

.device-card-list {
  flex: 1;
  overflow: hidden auto;
}

.device-card-empty {
  margin-top: 200px;
}

.device-card-container {
  position: relative;
  height: 328px;
  padding: 16px 24px;
  background-color: #fff;
  border-radius: 12px;
}

.device-card-header {
  display: flex;
  align-items: center;
  margin-bottom: 24px;
}

.device-card-header-title {
  max-width: 150px;
  margin-right: 16px;
  margin-left: 8px;
  font-size: 16px;
  font-weight: 600;
  line-height: 28px;
  color: var(--antd-color-text);
}

.ctrl-cabinet-mode {
  width: 86px;
  height: 24px;
  font-size: 14px;
  font-weight: 500;
  line-height: 22px;
  color: var(--antd-color-primary);
  text-align: center;
  background: var(--antd-color-primary-opacity-10);
  border: 1px solid var(--antd-color-primary);
  border-radius: 4px;
}

.device-cop-value {
  font-family: DINAlternate;
  font-size: 24px;
  font-weight: bold;
  line-height: 32px;
  color: #e6a23c;
  cursor: pointer;
}

.device-cop-level {
  width: 16px;
  height: 16px;
  margin-left: 8px;
  font-size: 12px;
  font-weight: 600;
  line-height: 16px;
  color: #e6a23c;
  text-align: center;
  cursor: pointer;
  background: rgb(234 178 94 / 40%);
  border-radius: 2px;
}

.device-card-header-time {
  flex: 1;
  font-size: 12px;
  font-weight: 500;
  line-height: 20px;
  color: #999;
  text-align: right;
}

.device-card-header-button {
  padding: 4px;
  margin-left: 16px;
  font-size: 16px;
  color: var(--antd-color-primary);
  cursor: pointer;
  background: var(--antd-color-primary-opacity-15);
  border-radius: 4px;
}

:deep(.device-card-label) {
  height: 20px;
  font-size: 12px;
  font-weight: 500;
  line-height: 20px;
  color: #999;

  + .progress-text-bar {
    margin-top: 4px;
    cursor: pointer;
  }
}

:deep(.device-card-value) {
  height: 24px;
  font-family: DINAlternate;
  font-size: 16px;
  font-weight: bold;
  line-height: 24px;
  color: #333;
  cursor: pointer;

  &.device-card-no-history {
    cursor: default;
  }
}
</style>
