import MyMap from '../my-map'
import {
  CallBack,
  MapConfig,
  Listeners,
  ControlOptions,
  ZoomOptions,
  FocusOptions,
  Location,
  ClickCallBack,
  Controls,
  AIMapConfig,
  Layers,
  LayerOption,
} from '../types'
import { toLines, toPoints, toPolygons } from './util'

/** 维智地图 */
export default class AI_Map extends MyMap {
  private _clickCb: ClickCallBack | null = null
  constructor(config: MapConfig<AIMapConfig>) {
    if (!config.appKey) {
      throw new Error('AIMap需要设置appKey参数！')
    }
    aimap.accessToken = config.appKey
    if (!config.baseApiUrl) {
      throw new Error('AIMap需要设置baseApiUrl参数！')
    }
    aimap.baseApiUrl = config.baseApiUrl

    const instance = new aimap.Map({
      container: config.el,
      center: config.center,
      zoom: config.zoom,
      minZoom: config.zooms?.[0],
      maxZoom: config.zooms?.[1],
      pitch: config.pitch || 0,
      minPitch: config.pitchs?.[0],
      maxPitch: config.pitchs?.[1],
      bearing: config.bearing || 0,
      style: config.style,
      localIdeographFontFamily: config.family,
    })
    super(instance)
    this._setListeners()
    this._setControls()
    this._setLayers()
  }

  /** 设置监听事件 */
  private _setListeners() {
    const _listeners: Partial<Listeners> = {
      load: (cb: CallBack) => {
        this.map.on('load', cb)
      },
      zoom: (cb: CallBack) => {
        this.map.on('zoom', cb)
      },
      move: (cb: CallBack) => {
        this.map.on('move', cb)
      },
      blur: (cb: CallBack) => {
        this.map.on('blur', cb)
      },
      focus: (cb: CallBack) => {
        this.map.on('focus', cb)
      },
      drag: (cb: CallBack) => {
        this.map.on('drag', cb)
      },
      resize: (cb: CallBack) => {
        this.map.on('resize', cb)
      },
      click: (cb: ClickCallBack) => {
        this._clickCb = cb
        this.map.on('click', (e: any) => {
          const arg = {
            type: e.type,
            center: [e.lngLat.lng, e.lngLat.lat],
            event: e.originalEvent,
            clientX: e.point.x,
            clientY: e.point.y,
            originData: e,
          }
          cb(arg)
        })
      },
    }
    this._listeners = Object.assign(this._listeners, _listeners)
  }

  /** 设置控制器 */
  private _setControls() {
    const _controls: Partial<Controls> = {
      compass: (options?: ControlOptions) => {
        this.map.addControl(new aimap.CompassControl(), options?.position)
      },
      zoom: (options?: ControlOptions) => {
        this.map.addControl(
          new aimap.NavigationControl({
            showZoom: options?.show,
            showCompass: false,
            visualizePitch: false,
          }),
          options?.position,
        )
      },
      scale: (options?: ControlOptions) => {
        this.map.addControl(
          new aimap.ScaleControl({
            maxWidth: options?.maxWidth || 80,
            unit: options?.unit || 'metric',
          }),
          options?.position,
        )
      },
    }
    this._controls = Object.assign(this._controls, _controls)
  }

  /** 设置覆盖物 */
  private _setLayers() {
    const makeLayer = (layer: any) => {
      layer.on('click', (e: any) => {
        const arg = {
          type: e.type,
          center: [e.lngLat.lng, e.lngLat.lat],
          event: e.originalEvent,
          clientX: e.point.x,
          clientY: e.point.y,
          originData: e,
        }
        // 点击覆盖物获取自定义数据
        this._clickCb && this._clickCb(arg, e?.features?.[0]?.properties)
      })
      return layer
    }
    const _layers: Partial<Layers> = {
      point: (data: LayerOption) =>
        makeLayer(new aimap.MassMarkerLayer(toPoints(this.map, data))),
      line: (data: LayerOption) =>
        makeLayer(new aimap.LineString(toLines(this.map, data))),
      polygon: (data: LayerOption) =>
        makeLayer(new aimap.Polygon(toPolygons(this.map, data))),
    }
    this._layers = Object.assign(this._layers, _layers)
  }

  zoomIn(options: ZoomOptions) {
    this.map.zoomIn(options)
  }
  zoomOut(options: ZoomOptions) {
    this.map.zoomOut(options)
  }
  zoomTo(level: number, options: ZoomOptions) {
    this.map.zoomTo(level, options)
  }
  focus(location: Location, options?: FocusOptions) {
    this.map.flyTo({
      center: location,
      ...options,
    })
  }
  remove(layer: any) {
    layer && layer.remove()
  }

  addBoundary() {
    console.error('此地图不存在 addBoundary 方法')
    return { remove: () => null }
  }
}
