<template>
  <div class="wrapper">
    <Spin :spinning="spinning">
      <div ref="wrapRef" :style="{ height, width }"> </div>
    </Spin>
    <div class="right-wrap !dark:bg-dark-900">
      <BasicTable
        style="cursor: pointer"
        @register="registerTable"
        @rowClick="deviceRowClick"
        class="dark:bg-dark-900"
      >
        <template #deviceState="{ record }">
          <Tag
            :color="
              record.deviceState == DeviceState.INACTIVE
                ? 'warning'
                : record.deviceState == DeviceState.ONLINE
                ? 'success'
                : 'error'
            "
            class="ml-2"
          >
            {{
              record.deviceState == DeviceState.INACTIVE
                ? '待激活'
                : record.deviceState == DeviceState.ONLINE
                ? '在线'
                : '离线'
            }}
          </Tag>
        </template>
        <template #alarmStatus="{ record }">
          <Tag :color="record.alarmStatus == 1 ? 'warning' : 'success'" class="ml-2">
            {{ record.alarmStatus == 1 ? '告警' : '正常' }}
          </Tag>
        </template>
      </BasicTable>
    </div>
    <BasicModal
      @register="registerModal"
      title="历史数据"
      width="70%"
      :minHeight="400"
      :footer="null"
      wrap-class-name="history-trend-model"
      :canFullscreen="false"
      @cancel="handleCancelModal"
    >
      <TimePeriodForm @register="timePeriodRegister" />
      <section>
        <Spin :spinning="loading">
          <div
            v-show="mode === EnumTableChartMode.CHART"
            class="flex h-70px items-center justify-end p-2"
          >
            <ModeSwitchButton
              v-model:value="mode"
              :mode="TABLE_CHART_MODE_LIST"
              @change="switchMode"
            />
          </div>
          <div
            v-show="isNull && mode === EnumTableChartMode.CHART"
            ref="chartRef"
            :style="{ height: '400px', width }"
          >
          </div>
          <Empty
            :style="{ height: '550px', width }"
            class="flex flex-col justify-center items-center"
            v-show="!isNull && mode === EnumTableChartMode.CHART"
          />

          <BasicTable v-show="mode === EnumTableChartMode.TABLE" @register="registerAttrTable">
            <template #toolbar>
              <div class="flex h-70px items-center justify-end p-2">
                <ModeSwitchButton
                  v-model:value="mode"
                  :mode="TABLE_CHART_MODE_LIST"
                  @change="switchMode"
                />
              </div>
            </template>
          </BasicTable>
        </Spin>
      </section>
    </BasicModal>
    <DeviceDetailDrawer
      @register="registerDetailDrawer"
      @open-tb-device-detail="handleOpenTbDeviceDetail"
      @open-gateway-device-detail="handleOpenGatewayDetail"
    />
    <DeviceDetailDrawer @register="registerTbDetailDrawer" />

    <DeviceDetailDrawer @register="registerGatewayDetailDrawer" />
  </div>
</template>
<script lang="ts">
  import {
    defineComponent,
    ref,
    nextTick,
    unref,
    onMounted,
    Ref,
    onUnmounted,
    computed,
  } from 'vue';
  import { useScript } from '/@/hooks/web/useScript';
  import { formSchema, columns, setMapStyleV2 } from './config.data';
  import { BasicTable, useTable } from '/@/components/Table';
  import { devicePage } from '/@/api/alarm/contact/alarmContact';
  import { Tag, Empty, Spin } from 'ant-design-vue';
  import { DeviceState } from '/@/api/device/model/deviceModel';
  import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
  import { useModal, BasicModal } from '/@/components/Modal';
  import { useECharts } from '/@/hooks/web/useECharts';
  import { getDeviceHistoryInfo, getDeviceActiveTime } from '/@/api/alarm/position';
  import { useDrawer } from '/@/components/Drawer';
  import DeviceDetailDrawer from '/@/views/device/list/cpns/modal/DeviceDetailDrawer.vue';
  import moment from 'moment';
  // 导入一些静态图片,避免打包时不能正确解析
  import djx from '/@/assets/images/djx.png';
  // import locationJx from '/@/assets/images/location.png';
  import zx from '/@/assets/images/zx.png';
  import lx from '/@/assets/images/lx.png';
  import djh from '/@/assets/images/djh.png';
  import online from '/@/assets/images/online1.png';
  import lx1 from '/@/assets/images/lx1.png';
  import { TimePeriodForm, useTimePeriodForm } from './cpns/TimePeriodForm';
  import { selectDeviceAttrSchema } from './config.data';
  import { defaultSchemas } from './cpns/TimePeriodForm/config';
  import { QueryWay, SchemaFiled, AggregateDataEnum } from './cpns/TimePeriodForm/config';
  import { useAsyncQueue } from './useAsyncQueue';
  import { useHistoryData } from '../list/hook/useHistoryData';
  import { formatToDateTime } from '/@/utils/dateUtil';
  import {
    TABLE_CHART_MODE_LIST,
    EnumTableChartMode,
    ModeSwitchButton,
  } from '/@/components/Widget';

  interface DeviceInfo {
    alarmStatus: 0 | 1;
    deviceState: string;
    tbDeviceId: string;
    name: string;
    organizationDTO: { name: string };
    deviceProfile: { default: boolean; enabled: boolean; name: string; transportType: string };
    deviceInfo: { longitude: string; latitude: string; address: string };
    deviceType?: string;
    deviceProfileId: string;
  }
  type MarkerList = DeviceInfo & { marker: any; label: any };

  export default defineComponent({
    name: 'BaiduMap',
    components: {
      BasicTable,
      Tag,
      Empty,
      BasicModal,
      DeviceDetailDrawer,
      TimePeriodForm,
      Spin,
      ModeSwitchButton,
    },
    props: {
      width: {
        type: String,
        default: '100%',
      },
      height: {
        type: String,
        default: 'calc(100vh - 78px)',
      },
    },
    setup() {
      const mode = ref<EnumTableChartMode>(EnumTableChartMode.CHART);
      let entityId = '';
      let globalRecord: any = {};
      const wrapRef = ref<HTMLDivElement | null>(null);
      const chartRef = ref<HTMLDivElement | null>(null);
      const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
      const isNull = ref(true);
      const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
      const [registerDetailDrawer, { openDrawer }] = useDrawer();
      const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer();
      const [registerGatewayDetailDrawer, { openDrawer: openGatewayDetailDrawer }] = useDrawer();
      const [registerModal, { openModal }] = useModal();
      const BMapInstance = ref<Nullable<any>>(null);

      const historyData = ref<{ ts: number; value: string; name: string }[]>([]);

      const loading = ref(false);

      const { deviceAttrs, getDeviceKeys, getDeviceAttribute, getSearchParams, setChartOptions } =
        useHistoryData();

      const getTableHistoryData = (record: Recordable<{ ts: number; value: string }[]>) => {
        const keys = Object.keys(record);
        const list = keys.reduce((prev, next) => {
          const list = record[next].map((item) => {
            return {
              ...item,
              name: next,
            };
          });
          return [...prev, ...list];
        }, []);
        return list;
      };

      const getIdentifierNameMapping = computed(() => {
        const mapping = {};
        unref(deviceAttrs).forEach((item) => {
          const { identifier, name } = item;
          mapping[identifier] = name;
        });
        return mapping;
      });

      const [registerAttrTable] = useTable({
        showIndexColumn: false,
        showTableSetting: false,
        dataSource: historyData,
        maxHeight: 300,
        size: 'small',
        columns: [
          {
            title: '属性',
            dataIndex: 'name',
            format: (text) => {
              return unref(getIdentifierNameMapping)[text];
            },
          },
          {
            title: '值',
            dataIndex: 'value',
          },
          {
            title: '更新时间',
            dataIndex: 'ts',
            format: (val) => {
              return formatToDateTime(val, 'YYYY-MM-DD HH:mm:ss');
            },
          },
        ],
      });

      const [registerTable] = useTable({
        api: devicePage,
        columns,
        resizeHeightOffset: 32,
        formConfig: {
          schemas: formSchema,
          labelAlign: 'left',
        },
        beforeFetch: (params) => {
          const { deviceProfileId } = params;
          const deviceProfileIds = [deviceProfileId];
          const obj = {
            ...params,
            ...{
              deviceProfileIds: params?.deviceProfileId === undefined ? null : deviceProfileIds,
            },
          };
          delete obj.deviceProfileId;
          return obj;
        },
        showIndexColumn: false,
        useSearchForm: true,
        pagination: {
          showQuickJumper: false,
          showSizeChanger: true,
        },
        afterFetch: async (data: DeviceInfo[]) => {
          if (!(window as any).BMap) {
            clearTask();
            setTask(createMarket.bind(null, data));
            return data;
          }
          createMarket(data);
          return data;
        },
      });
      const { setTask, clearTask, executeFlag } = useAsyncQueue();

      let interval: Nullable<NodeJS.Timer> = setInterval(() => {
        if ((window as any).BMap) {
          executeFlag.value = true;
          clearInterval(interval!);
          interval = null;
        }
      }, 1000);

      async function createMarket(data: DeviceInfo[]) {
        const BMap = (window as any).BMap;
        if (!BMap) {
          return;
        }
        unref(BMapInstance)?.clearOverlays();
        const markerList: MarkerList[] = [];
        data.forEach((item) => {
          const {
            name,
            deviceState,
            deviceInfo: { longitude, latitude },
          } = item;
          const point = new BMap.Point(longitude, latitude);
          const rivet = deviceState === 'INACTIVE' ? djx : deviceState === 'ONLINE' ? zx : lx;
          const myIcon = new BMap.Icon(rivet, new BMap.Size(20, 30));
          const marker = new BMap.Marker(point, { icon: myIcon });
          const label = new BMap.Label(name, {
            position: point,
            offset: new BMap.Size(-15, -45),
          });
          label.setStyle({
            color: '#000',
            borderRadius: '5px',
            borderColor: '#ccc',
            padding: '5px',
          });
          markerList.push({ ...item, marker, label });
        });

        markerList.forEach((record) => {
          unref(BMapInstance)?.addOverlay(record.marker);
          unref(BMapInstance)?.addOverlay(record.label);
          const isAlarmStatus = !!record.alarmStatus;
          if (isAlarmStatus) {
            const alarmStatusClassName = 'device-status__alarm';
            const className = record.marker?.Ec?.getAttribute('class');
            if (record.marker?.Ec) {
              record.marker?.Ec?.setAttribute('class', `${className} ${alarmStatusClassName}`);
            }
          }

          //标注监听事件
          record.marker.addEventListener('click', function () {
            createDeviceInfoWindow(record);
          });
        });
      }

      async function initMap() {
        await toPromise();
        await nextTick();
        const wrapEl = unref(wrapRef);
        const BMap = (window as any).BMap;
        if (!wrapEl) return;
        BMapInstance.value = new BMap.Map(wrapEl);
        function myFun(result) {
          let mk = new BMap.Marker(result.center);
          unref(BMapInstance).addOverlay(mk);
          unref(BMapInstance).panTo(result.center);
          unref(BMapInstance).centerAndZoom(result.center, 15);
          unref(BMapInstance).enableScrollWheelZoom(true);
          unref(BMapInstance).setMapStyleV2(setMapStyleV2);
        }
        let myCity = new BMap.LocalCity();
        myCity.get(myFun);
      }

      const spinning = ref(false);
      const createDeviceInfoWindow = async (record: DeviceInfo) => {
        const BMap = (window as any).BMap;
        entityId = record.tbDeviceId;
        globalRecord = record;
        try {
          await getDeviceAttribute(record);
        } catch (error) {}

        const options = {
          width: 330, // 信息窗口宽度
          height: 0, // 信息窗口高度
        };
        const { name, organizationDTO, deviceState, deviceProfile, deviceType } = record;
        const { address, longitude, latitude } = record.deviceInfo;

        // 创建信息窗口对象
        const res = await getDeviceActiveTime(entityId);

        let { lastUpdateTs } = res[0];
        lastUpdateTs = moment(lastUpdateTs).format('YYYY-MM-DD HH:mm:ss');
        let infoWindow = new BMap.InfoWindow(
          `
          <div style="display:flex;justify-content:space-between; margin:20px 0px;">
            <div style="font-size:16px;font-weight:bold">${name}</div>
            ${
              deviceState === 'INACTIVE'
                ? `<div style="display:flex;align-items:center;"><img style="width:15px;height:15px" src="${djh}" class="mr-1">待激活</div>`
                : deviceState === 'ONLINE'
                ? `<div style="display:flex;align-items:center; ">
                <img style="width:15px;height:15px" src="${online}" class="mr-1">在线</div>`
                : `<div style="display:flex;align-items:center;"><img style="width:15px;height:15px" src="${lx1}" class="mr-1">离线</div>`
            }
          </div>
          <div>所属组织：${organizationDTO.name}</div>
          <div style="margin-top:6px;">接入协议：${deviceProfile.transportType}</div>
          <div style="margin-top:6px;">
            设备位置：${address == '' ? '该设备暂无地理位置' : address}
          </div>
          <div style="margin-top:6px;">
            ${
              deviceState === 'ONLINE' ? '在线' : deviceState === 'INACTIVE' ? '创建' : '离线'
            }时间：${lastUpdateTs}
            </div>
          <div style="display:flex;justify-content:end; margin-top:10px">
            <button onclick="openDeviceInfoDrawer()" style="margin-right:10px;color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button>
            <button onclick="openHistoryModal()" style="display:${
              deviceType !== 'GATEWAY' ? 'block' : 'none'
            };color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">${
            deviceType !== 'GATEWAY' ? '历史数据' : ''
          }</button>
          </div>
          `,
          options
        );

        const point = new BMap.Point(
          longitude || 104.04666605565338,
          latitude || 30.543516387560476
        );

        if (!longitude || !latitude)
          infoWindow = new BMap.InfoWindow('该设备暂无地理位置', options); // 创建信息窗口对象
        unref(BMapInstance).centerAndZoom(point, 15);
        unref(BMapInstance).openInfoWindow(infoWindow, unref(BMapInstance).getCenter());
      };
      // 点击表格某一行触发
      const deviceRowClick = async (record) => {
        try {
          spinning.value = true;
          await createDeviceInfoWindow(record);
        } catch (err) {
        } finally {
          spinning.value = false;
        }
      };

      // 设备信息
      const openDeviceInfoDrawer = async () => {
        const { id, tbDeviceId } = globalRecord;
        openDrawer(true, {
          id,
          tbDeviceId,
        });
      };

      const [timePeriodRegister, method] = useTimePeriodForm({
        schemas: [...defaultSchemas, ...selectDeviceAttrSchema],
        async submitFunc() {
          // 表单验证
          await method.validate();
          const value = method.getFieldsValue();
          const searchParams = getSearchParams(value);

          if (!hasDeviceAttr()) return;
          // 发送请求
          loading.value = true;
          const res = await getDeviceHistoryInfo({ ...searchParams, entityId });
          loading.value = false;
          historyData.value = getTableHistoryData(res);
          // 判断数据对象是否为空
          if (!Object.keys(res).length) {
            isNull.value = false;
            return;
          } else {
            isNull.value = true;
          }
          const selectedKeys = unref(deviceAttrs).find(
            (item) => item.identifier === value[SchemaFiled.KEYS]
          );
          setOptions(setChartOptions(res, selectedKeys));
        },
      });

      const openHistoryModal = async () => {
        openModal(true);

        await nextTick();
        method.updateSchema({
          field: 'keys',
          componentProps: {
            options: unref(deviceAttrs).map((item) => ({
              label: item.name,
              value: item.identifier,
            })),
          },
        });

        method.setFieldsValue({
          [SchemaFiled.START_TS]: 1 * 24 * 60 * 60 * 1000,
          [SchemaFiled.LIMIT]: 7,
          [SchemaFiled.AGG]: AggregateDataEnum.NONE,
        });

        if (!hasDeviceAttr()) return;

        const res = await getDeviceHistoryInfo({
          entityId,
          keys: unref(getDeviceKeys).join(),
          startTs: Date.now() - 1 * 24 * 60 * 60 * 1000,
          endTs: Date.now(),
          agg: AggregateDataEnum.NONE,
          limit: 7,
        });

        historyData.value = getTableHistoryData(res);
        // 判断对象是否为空
        if (!Object.keys(res).length) {
          isNull.value = false;
          return;
        } else {
          isNull.value = true;
        }
        setOptions(setChartOptions(res));
      };
      function hasDeviceAttr() {
        if (!unref(deviceAttrs).length) {
          isNull.value = false;
          return false;
        } else {
          isNull.value = true;
          return true;
        }
      }

      const handleCancelModal = () => {
        method.setFieldsValue({
          [SchemaFiled.WAY]: QueryWay.LATEST,
          [SchemaFiled.KEYS]: null,
          [SchemaFiled.DATE_RANGE]: [],
          [SchemaFiled.INTERVAL]: null,
          [SchemaFiled.LIMIT]: 7,
          [SchemaFiled.AGG]: AggregateDataEnum.NONE,
        });
        getInstance()?.clear();
      };

      onMounted(() => {
        initMap();
        (window as any).openDeviceInfoDrawer = openDeviceInfoDrawer;
        (window as any).openHistoryModal = openHistoryModal;
      });

      onUnmounted(() => {
        (window as any).openDeviceInfoDrawer = null;
        (window as any).openHistoryModal = null;
      });

      const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {
        openTbDeviceDrawer(true, data);
      };

      const handleOpenGatewayDetail = (data: { id: string; tbDeviceId: string }) => {
        openGatewayDetailDrawer(true, data);
      };

      const switchMode = (flag: EnumTableChartMode) => {
        mode.value = flag;
      };

      return {
        mode,
        EnumTableChartMode,
        TABLE_CHART_MODE_LIST,
        wrapRef,
        registerTable,
        deviceRowClick,
        DeviceState,
        registerModal,
        chartRef,
        isNull,
        registerDetailDrawer,
        loading,
        spinning,
        timePeriodRegister,
        handleCancelModal,
        registerTbDetailDrawer,
        registerGatewayDetailDrawer,
        handleOpenTbDeviceDetail,
        handleOpenGatewayDetail,
        switchMode,
        registerAttrTable,
      };
    },
  });
</script>
<style scoped lang="less">
  .wrapper {
    position: relative;

    :deep(.BMap_shadow) {
      display: none;
    }
  }

  .right-wrap {
    padding-top: 10px;
    width: 28%;
    height: 95%;
    position: absolute;
    right: 5%;
    top: 3%;
    background-color: #fff;
  }
</style>
<style>
  .history-trend-model .ant-input-number {
    min-width: 0 !important;
    width: 100% !important;
  }

  .device-status__alarm {
    transform-origin: 10px 15px;
    animation: 0.5s linear 0s infinite alternate Scale;
  }

  @keyframes Scale {
    0% {
      /* transform: translateY(0px); */
      transform: scale(1);
    }

    50% {
      /* transform: translateY(5px); */
      transform: scale(1.5);
    }

    100% {
      /* transform: translateY(10px); */
      transform: scale(2);
    }
  }
</style>
