import vjmap, { Map, GeoBounds, GeoProjection } from 'vjmap';
// import { App, MapThreeLayer } from 'vjmap3d';
import 'vjmap/dist/vjmap.min.css';
import { useAppStore } from '/@/store/modules/app';
import { message, Modal } from 'ant-design-vue';
import { updatateGoaf } from './cad.api';
import { createApp, h } from 'vue';
import GoafPopup from './components/GoafPopup.vue';
import { get, remove } from 'lodash-es';
import { StatusColorEnum } from '/@/enums/jeecgEnum';

import customImage from '/@/assets/icons/location-icon.svg';
import customImage3D from '/@/assets/icons/location-icon3D.png';
import { env } from './env';
import { tryOnUnmounted } from '@vueuse/core';

export type UseMap2DOptions = {
  // fileUrl?: string;
  style?: vjmap.IMapStyleParam;
  wjId?: string;
};

export type GoafItem = Record<string, any>;

export type MarkerStatus = {
  sensorId: any;
  id: any;
  data: any;
  lnglat: any;
  position: any;
};

export type UseMap2DReturn = {
  map: vjmap.Map | null;
  initMap2d: (container: HTMLElement, config?: UseMap2DOptions) => Promise<Map>;
  destroyMap: () => void;
  bindPosition: (props?: any) => Promise<any | null>;
  removePosition: (sensorId: number | string, id: string | number) => Promise<boolean>;
  getMarkerStatusList: () => MarkerStatus[];
  getGoafIsPositioned: (goafItem: any) => boolean;
  renderGoafMarkers: (goafList: any[]) => void;
};

export function useMap2D(): UseMap2DReturn {
  const allMarkers: any[] = [];
  let prj: GeoProjection | null = null;
  let map: vjmap.Map | null = null;
  let sensorId = 1;
  let currentPopup: any = null;

  const svc = new vjmap.Service(env.serviceUrl, env.accessToken);

  const destroyMap = (): void => {
    closeAndCleanPopup();
    cleanMarkers();
    if (map) {
      map?.destory();
    }
    map = null;
    prj = null;
  };

  tryOnUnmounted(destroyMap);

  async function initMap2d(container: HTMLElement, config: UseMap2DOptions = {}): Promise<Map> {
    if (!container) {
      message.error('地图容器不存在！');
      throw new Error('地图容器不存在！');
    }

    destroyMap();

    const appStore = useAppStore();
    const { style = vjmap.openMapLightStyle(), wjId = 'c96e7423dab1' } = config;

    container.style.background = 'transparent';
    container.style.width = `${get(container, 'parentElement.clientWidth', 0) / appStore.widthScale}px`;
    container.style.height = `${get(container, 'parentElement.clientHeight', 0) / appStore.heightScale}px`;

    const res = await svc.openMap({
      mapid: wjId,
      fileid: wjId,
      mapopenway: vjmap.MapOpenWay.GeomRender,
      style,
    });

    if (res.error) {
      message.error(`地图加载失败：${res.error}`);
      console.error(res.error);
    }

    const mapExtent = GeoBounds.fromString(res.bounds);
    prj = new GeoProjection(mapExtent);

    map = new vjmap.Map({
      container,
      style: svc.rasterStyle(),
      center: prj.toLngLat(mapExtent.center()),
      zoom: 8,
      antialias: true,
      renderWorldCopies: false,
    });

    map.attach(svc, prj);
    map.fitMapBounds();
    await map.onLoad();

    return map;
  }

  function isValidSingleCoord(coord: any): boolean {
    return coord && coord.trim() !== '' && !isNaN(Number(coord));
  }

  function getGoafIsPositioned(goafItem: any): boolean {
    const hasValidX = isValidSingleCoord(goafItem.xcoordinate);
    const hasValidY = isValidSingleCoord(goafItem.ycoordinate);
    return hasValidX && hasValidY;
  }

  function getMarkerStatusList(): MarkerStatus[] {
    if (!map) return [];
    return allMarkers.map((marker) => ({
      sensorId: marker.data?.sensorId,
      id: marker.data?.id,
      data: marker.data,
      lnglat: marker.getLngLat(),
      position: map?.fromLngLat(marker.getLngLat()),
    }));
  }

  function syncLocalStorage(): void {
    if (!map) return;
    const markerData = allMarkers.map((m) => ({
      position: map?.fromLngLat(m.getLngLat()),
      data: m.data,
    }));
    localStorage.setItem('marker_sensor', JSON.stringify(markerData));
  }

  function closeAndCleanPopup(): void {
    currentPopup?.remove();
    currentPopup = null;
  }

  async function pickPoint(markerOptions: any): Promise<any | null> {
    if (!map) return null;

    let marker: any = null;
    const actionPoint = await vjmap.Draw.actionDrawPoint(map, {
      updatecoordinate: (e: any) => {
        if (!e.lnglat) return;
        if (!marker) {
          marker = vjmap.createMarker(markerOptions);
          marker.setLngLat(e.lnglat);
          marker.addTo(map);
        } else {
          marker.setLngLat(e.lnglat);
        }
      },
      contextMenu: (e: any) => {
        new vjmap.ContextMenu({
          event: e.event.originalEvent,
          theme: 'dark',
          width: '250px',
          items: [
            {
              label: '取消',
              onClick: () => map?.fire('keyup', { keyCode: 27 }),
            },
          ],
        });
      },
    });

    if (actionPoint.cancel) {
      marker?.remove();
      return null;
    }
    return marker;
  }

  function bindMarkerEvents(marker: any, id: string | number): void {
    marker.setDraggable(false);
    let isDragging = false;

    marker.on('dragstart', () => {
      isDragging = false;
    });
    marker.on('dragend', () => {
      setTimeout(() => {
        isDragging = false;
      }, 150);
      const lnglat = marker.getLngLat();
      if (id) {
        updatateGoaf({
          id,
          xcoordinate: lnglat.lng.toString(),
          ycoordinate: lnglat.lat.toString(),
        }).catch((err: Error) => {
          message.error(`拖拽后同步坐标失败：${err.message}`);
        });
      }
    });

    marker.getElement().addEventListener('click', () => {
      if (!isDragging) {
        showMarkerPopup(marker);
      }
    });
  }

  function createMarkerElement(goafItem: any, showInfo: boolean = false): HTMLDivElement {
    const riskMap = {
      '1': '低风险',
      '2': '一般风险',
      '3': '较高风险',
      '4': '高风险',
    };

    const alarmLevelColor = [StatusColorEnum.blue, StatusColorEnum.yellow, StatusColorEnum.gold, StatusColorEnum.red];
    const el = document.createElement('div');
    el.className = 'marker';
    el.style.cssText = `
      display: flex;
      flex-direction: column;
      align-items: center;
      cursor: move;
    `;

    const level = parseInt(goafItem.alarmLevel, 10);
    const color = level >= 1 && level <= 4 ? alarmLevelColor[level - 1] : '#333';

    if (showInfo) {
      const alarmLevelDiv = document.createElement('div');
      alarmLevelDiv.style.cssText = `
        font-size: 14px;
        white-space: nowrap;
        font-weight: bold;
        display: flex;
        align-items: center;
      `;

      const labelSpan = document.createElement('span');
      labelSpan.textContent = '风险等级：';
      labelSpan.style.color = '#333';

      const valueSpan = document.createElement('span');
      const riskText = riskMap[String(goafItem.alarmLevel)] || '正常';
      valueSpan.textContent = goafItem.alarmLevel ? riskText : '正常';
      valueSpan.style.color = color;

      alarmLevelDiv.appendChild(labelSpan);
      alarmLevelDiv.appendChild(valueSpan);
      el.appendChild(alarmLevelDiv);
    }

    const iconDiv = document.createElement('div');
    iconDiv.style.cssText = `
      background-image: url("${showInfo ? customImage3D : customImage}");
      width: 40px;
      height: 45px;
      background-size: 100% 100%;
      background-position: center;
      background-repeat: no-repeat;
    `;
    el.appendChild(iconDiv);

    if (showInfo) {
      const devicePosDiv = document.createElement('div');
      devicePosDiv.style.cssText = `
        position: absolute;
        font-size: 14px;
        color: #333;
        margin-top: 2px;
        white-space: nowrap;
        max-width: 120px;
        overflow: hidden;
        text-overflow: ellipsis;
        bottom: -20px;
      `;
      devicePosDiv.textContent = goafItem.devicePos;
      el.appendChild(devicePosDiv);
    }

    return el;
  }

  function showMarkerPopup(marker: any): void {
    if (!map) return;

    closeAndCleanPopup();

    const lnglat = marker.getLngLat();
    const data = marker.data || {};

    const tempContainer = document.createElement('div');
    const popupApp = createApp({
      render: () => h(GoafPopup, { data }),
    });
    popupApp.mount(tempContainer);

    currentPopup = new vjmap.Popup({
      closeButton: true,
      closeOnClick: false,
      maxWidth: '800px',
      offset: [0, 0],
    })
      .setLngLat(lnglat)
      .setDOMContent(tempContainer)
      .addTo(map);

    currentPopup.on('close', () => {
      popupApp.unmount();
      tempContainer.remove();
      currentPopup = null;
    });
  }

  async function bindPosition(props?: any): Promise<any | null> {
    if (!map) {
      message.error('地图未初始化完成，请先加载地图！');
      return null;
    }

    map.fire('keyup', { keyCode: 27 });

    const el = createMarkerElement(
      {
        alarmLevel: props?.alarmLevel,
        devicePos: props?.devicePos,
      },
      false
    );

    const markerOptions: vjmap.createMarkerOptions = {
      element: el,
      anchor: 'bottom',
      offset: [0, 0],
    };

    let marker: any = null;
    if (!props || !props.position) {
      marker = await pickPoint(markerOptions);
      if (!marker) return null;

      const confirmResult = await new Promise<boolean>((resolve) => {
        Modal.confirm({
          title: '保存布点',
          content: '是否确认保存该布点？',
          okText: '确定',
          cancelText: '取消',
          maskClosable: false,
          centered: true,
          onOk: () => resolve(true),
          onCancel: () => resolve(false),
        });
      });

      if (!confirmResult) {
        marker.remove();
        return null;
      }

      const lnglat = marker.getLngLat();
      const id = props?.id;
      if (!id) {
        marker.remove();
        message.error('缺少密闭ID，无法同步布点信息到服务器');
        throw new Error('缺少密闭ID，无法同步布点信息到服务器');
      }

      try {
        await updatateGoaf({
          id,
          xcoordinate: lnglat.lng.toString(),
          ycoordinate: lnglat.lat.toString(),
        });
      } catch (apiError) {
        marker.remove();
        message.error(`同步布点信息失败：${(apiError as Error).message}`);
        throw new Error(`同步布点信息失败：${(apiError as Error).message}`);
      }

      const currentLngLat = marker.getLngLat();
      marker.remove();

      const finalEl = createMarkerElement(
        {
          alarmLevel: props?.alarmLevel,
          devicePos: props?.devicePos,
        },
        true
      );

      marker = vjmap.createMarker({
        element: finalEl,
        anchor: 'bottom',
        offset: [0, 0],
      });
      marker.setLngLat(currentLngLat);
      marker.addTo(map);
      marker.data = {
        sensorId: sensorId++,
        id,
        ...(props || {}),
      };
    } else {
      if (!Array.isArray(props.position)) {
        throw new Error('预设坐标position格式错误，必须是[x, y]数组');
      }
      const lngLat = map.toLngLat(props.position);
      if (!lngLat) {
        throw new Error('转换坐标失败，无效的position');
      }

      marker = vjmap.createMarker(markerOptions);
      marker.setLngLat(lngLat);
      marker.data = {
        ...props.data,
        sensorId: props.data?.sensorId || sensorId++,
        id: props.data?.id || props.id,
        ...(props || {}),
      };
      marker.addTo(map);
    }

    bindMarkerEvents(marker, marker.data?.id);
    allMarkers.push(marker);
    syncLocalStorage();

    return {
      sensorId: marker.data.sensorId,
      id: marker.data.id,
      lnglat: marker.getLngLat(),
      xcoordinate: marker.getLngLat().lng.toString(),
      ycoordinate: marker.getLngLat().lat.toString(),
    };
  }

  function renderGoafMarkers(goafList: any[]): void {
    if (!map || !prj) {
      message.error('地图或投影坐标系未初始化完成！');
      return;
    }

    cleanMarkers();

    const validGoafList = goafList.filter((item) => getGoafIsPositioned(item));
    if (validGoafList.length === 0) {
      console.info('当前密闭列表无有效布点坐标，暂无标记可渲染');
      return;
    }

    for (const goafItem of validGoafList) {
      try {
        const lnglat = new vjmap.LngLat(Number(goafItem.xcoordinate), Number(goafItem.ycoordinate));
        const el = createMarkerElement(goafItem, true);

        const marker = vjmap.createMarker({
          element: el,
          anchor: 'bottom',
          offset: [0, 0],
        });
        marker.setLngLat(lnglat);
        // @ts-ignore next-line
        marker.data = {
          sensorId: sensorId++,
          id: goafItem.id,
          ...goafItem,
        };
        marker.addTo(map);

        bindMarkerEvents(marker, goafItem.id);
        allMarkers.push(marker);
      } catch (err) {
        console.error(`渲染密闭${goafItem.id}标记失败：`, err);
      }
    }
  }

  function cleanMarkers(): void {
    allMarkers.forEach((marker) => marker.remove());
    allMarkers.length = 0;
    sensorId = 1;
  }

  async function removePosition(__, id) {
    const marker = allMarkers.find((marker) => marker.data.id === id);
    if (marker) {
      const confirmResult = await new Promise<boolean>((resolve) => {
        Modal.confirm({
          title: '移除布点',
          content: '是否确认移除该布点？',
          okText: '确定',
          cancelText: '取消',
          maskClosable: false,
          centered: true,
          onOk: () => resolve(true),
          onCancel: () => resolve(false),
        });
      });

      if (!confirmResult) {
        return false;
      }

      try {
        await updatateGoaf({
          id,
          xcoordinate: '',
          ycoordinate: '',
        });
      } catch (apiError) {
        message.error(`同步布点信息失败：${(apiError as Error).message}`);
        return false;
      }

      marker.remove();
      remove(allMarkers, (marker) => marker.data.id === id);
      syncLocalStorage();

      return true;
    } else {
      message.error(`布点信息不存在`);
      return false;
    }
  }

  return {
    map,
    initMap2d,
    destroyMap,
    bindPosition,
    removePosition,
    getMarkerStatusList,
    getGoafIsPositioned,
    renderGoafMarkers,
  };
}

const defaultMap2DInstance: { current: UseMap2DReturn | null } = { current: null };
const getDefaultMap2D = (): UseMap2DReturn => {
  if (!defaultMap2DInstance.current) {
    defaultMap2DInstance.current = useMap2D();
  }
  return defaultMap2DInstance.current;
};

export const initMap2d = (container: HTMLElement, config: UseMap2DOptions = {}) => getDefaultMap2D().initMap2d(container, config);
export const destroyMap = () => getDefaultMap2D().destroyMap();
export const bindPosition = (props?: any) => getDefaultMap2D().bindPosition(props);
export const removePosition = (sensorId: number | string, id: string | number) => getDefaultMap2D().removePosition(sensorId, id);
export const getMarkerStatusList = () => getDefaultMap2D().getMarkerStatusList();
export const getGoafIsPositioned = (goafItem: any) => getDefaultMap2D().getGoafIsPositioned(goafItem);
export const renderGoafMarkers = (goafList: any[]) => getDefaultMap2D().renderGoafMarkers(goafList);
