    import { Evented, Zondy } from '../../../base'
    import { defaultValue, getGUID, defined, toJSON } from '../../../util'
    import {
      FetchMethod,
      LayerEventType,
      LayerType,
      LoadStatus
    } from '../../../base/enum'
    import { LayerViewUpdateEvent } from '../../../base/event'
    import SpatialReference from '../../../base/geometry/SpatialReference'
    import { Extent } from '../../../base/geometry'

    /**
     * 图层基类
     * @class Layer
     * @moduleEX LayerModule
     * @extends Evented
     * @fires Layer#图层加载完毕事件
     * @fires Layer#图层销毁完毕事件
     * @fires Layer#图层更新完毕事件
     * @fires Layer#图层显隐更新完毕事件
     * @fires Layer#图层透明度更新完毕事件
     * @fires Layer#图层顺序更新完毕事件
     * @fires Layer#图层刷新完毕事件
     * @param {Object} options 构造参数
     * @param {String} [options.title] 图层名称
     * @param {SpatialReference} [options.spatialReference] 图层坐标系
     * @param {Number} [options.minScale = 0] 最小缩放级数，仅会请求级数大于等于minScale的图片
     * @param {Number} [options.maxScale = 19] 最大缩放级数，仅会请求级数小于等于maxScale的图片
     * @param {String} [options.tokenKey = 'token'] token名
     * @param {String} [options.tokenValue] token值，只有当tokenValue存在时，才会绑定token
     * @param {Object} [options.extendProps] 存储额外参数的属性
     */

    /**
     * 图层加载完毕事件
     * @event Layer#图层加载完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-created'] 图层加载完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.UpdateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h7>图层加载完毕事件</h7></caption>
     * Layer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     * });
     */

    /**
     * 图层销毁完毕事件
     * @event Layer#图层销毁完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-remove'] 图层销毁完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 要销毁的地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h7>图层销毁完毕事件</h7></caption>
     * Layer.on('layerview-remove', function (result) {
     *   console.log("销毁完毕:", result.layer)
     * });
     */

    /**
     * 图层更新完毕事件
     * @event Layer#图层更新完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-update'] 图层更新完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h7>图层更新完毕事件</h7></caption>
     * Layer.on('layerview-update', function (result) {
     *   console.log("更新完毕:", result.layer)
     * });
     */

    /**
     * 图层显隐更新完毕事件，请注意该事件是图层更新事件(layerview-update)的子事件
     * @event Layer#图层显隐更新完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-update'] 图层更新完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h5>图层显隐更新完毕事件</h5></caption>
     * Layer.on('layerview-update', function (event) {
     *   // 获取更新事件对象
     *   console.log("更新完毕:", event)
     *   // 获取更新详情数组
     *   const updateContent = event.updateContent
     *   // 循环数组，根据事件名进行后续操作
     *   for (let i = 0; i < updateContent.length; i++) {
     *     // 图层显隐事件
     *     if(updateContent[i].name === 'visible'){
     *       console.log("图层显隐更新事件:", event);
     *     }
     *   }
     * });
     */

    /**
     * 图层透明度更新完毕事件，请注意该事件是图层更新事件(layerview-update)的子事件
     * @event Layer#图层透明度更新完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-update'] 图层更新完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h5>图层透明度更新完毕事件</h5></caption>
     * Layer.on('layerview-update', function (event) {
     *   // 获取更新事件对象
     *   console.log("更新完毕:", event)
     *   // 获取更新详情数组
     *   const updateContent = event.updateContent
     *   // 循环数组，根据事件名进行后续操作
     *   for (let i = 0; i < updateContent.length; i++) {
     *     // 图层透明度更新事件
     *     if(updateContent[i].name === 'opacity'){
     *       console.log("图层透明度更新事件:", event);
     *     }
     *   }
     * });
     */

    /**
     * 图层顺序更新完毕事件，请注意该事件是图层更新事件(layerview-update)的子事件
     * @event Layer#图层顺序更新完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-update'] 图层更新完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h5>图层顺序更新完毕事件</h5></caption>
     * Layer.on('layerview-update', function (event) {
     *   // 获取更新事件对象
     *   console.log("更新完毕:", event)
     *   // 获取更新详情数组
     *   const updateContent = event.updateContent
     *   // 循环数组，根据事件名进行后续操作
     *   for (let i = 0; i < updateContent.length; i++) {
     *     // 图层顺序更新完毕事件
     *     if(updateContent[i].name === 'index'){
     *       console.log("图层顺序更新完毕事件:", event);
     *     }
     *   }
     * });
     */

    /**
     * 图层刷新完毕事件，请注意该事件是图层更新事件(layerview-update)的子事件
     * @event Layer#图层刷新完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-update'] 图层更新完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h5>图层刷新完毕事件</h5></caption>
     * Layer.on('layerview-update', function (event) {
     *   // 获取更新事件对象
     *   console.log("更新完毕:", event)
     *   // 获取更新详情数组
     *   const updateContent = event.updateContent
     *   // 循环数组，根据事件名进行后续操作
     *   for (let i = 0; i < updateContent.length; i++) {
     *     // 图层刷新完毕事件
     *     if(updateContent[i].name === 'refresh'){
     *       console.log("图层刷新完毕事件:", event);
     *     }
     *   }
     * });
     */
    class Layer extends Evented {
      constructor(options) {
        super()
        // eslint-disable-next-line no-param-reassign
        options = defaultValue(options, {})
        /**
         * 图层id
         * @readonly
         * @member {String} Layer.prototype.id
         */
        this.id = defaultValue(options.id, getGUID())
        /**
         * 图层描述
         * @readonly
         * @member {String} Layer.prototype.description
         */
        this.description = defaultValue(options.description, '图层基类')
        /**
         * 版权所有
         * @readonly
         * @member {String} Layer.prototype.copyright
         */
        this.copyright = defaultValue(options.copyright, '中地数码版权所有')
        /**
         * 图层加载状态
         * @readonly
         * @default not-loaded
         * @member {String} Layer.prototype.loadStatus
         */
        this.loadStatus = defaultValue(options.loadStatus, LoadStatus.notLoaded)
        /**
         * 是否加载完毕
         * @readonly
         * @default false
         * @member {Boolean} Layer.prototype.loaded
         */
        this.loaded = false

        /**
         * token名
         * @default token
         * @member {String} Layer.prototype.tokenKey
         */
        this.tokenKey = defaultValue(options.tokenKey, 'token')
        /**
         * token值
         * @member {String} Layer.prototype.tokenValue
         */
        this.tokenValue = defaultValue(options.tokenValue, undefined)
        /**
         * 图层顺序
         * @member {Number} Layer.prototype.index
         */
        this.index = defaultValue(options.index, undefined)
        /**
         * 图层名称
         * @member {String} Layer.prototype.title
         */
        this.title = defaultValue(options.title, undefined)
        /**
         * 最小缩放级数，仅会请求级数大于等于minScale的图片
         * @default 0
         * @member {Number} Layer.prototype.minScale
         */
        this.minScale = defaultValue(options.minScale, undefined)
        /**
         * 最大缩放级数，仅会请求级数小于等于maxScale的图片
         * @default 19
         * @member {Number} Layer.prototype.maxScale
         */
        this.maxScale = defaultValue(options.maxScale, undefined)
        /**
         * 存储额外参数的属性
         * @member {Object} Layer.prototype.extendProps
         */
        this.extendProps = defaultValue(options.extendProps, {})
        /**
         * 图层类型
         * @readonly
         * @member {String} Layer.prototype.type
         */
        this.type = LayerType.baseLayer
        /**
         * http请求方式
         * @member {String} Layer.prototype.httpMethod
         */
        this.httpMethod = defaultValue(options.httpMethod, FetchMethod.get)
        // 图层显隐私有对象
        this._visible = defaultValue(options.visible, true)
        // 透明度私有对象
        this._opacity = parseFloat(defaultValue(options.opacity, 1))
        // 私有图层坐标系对象
        this._spatialReference = options.spatialReference
          ? SpatialReference.fromJSON(options.spatialReference)
          : undefined
        // 扩展属性key
        this._extendPropertyKeys = []
        // 实际图层顺序
        this._realIndex = undefined
        this._isFromJSON = false
        // 是否是basemap上的baseLayer
        this._isBasemapLayer = false
      }

      /**
       * @description 判断图层是否加载成功
       * @return {Boolean} 图层是否加载成功
       */
      isLoaded() {
        return this.loadStatus === LoadStatus.loaded
      }

      /**
       * @function Layer.load
       * @description 图层资源加载
       * @return {Promise<Layer>} 资源加载完毕的图层
       */
      load() {
        if (this._isFromJSON) {
          return new Promise((resolve, reject) => {
            this.loadStatus = LoadStatus.loaded
            this.loaded = true
            resolve(this)
            reject('资源请求失败!')
          })
        } else {
          return this._load()
        }
      }

      /**
       * @function setMap
       * @description 设置图层管理容器
       */
      setMap(map) {
        this._map = map
      }

      destroy() {}

      /**
       * @function extendProperty
       * @description 属性扩展
       * @param {String} key 属性名
       * @param {any} value 默认属性值
       */
      extendProperty(key, value) {
        if (!defined(this[key])) {
          // 添加扩展的属性字段
          this._extendPropertyKeys.push(key)
          this[key] = value
        }
      }

      /**
       * @private
       * @description 封装发送的更新事件
       * @param {String} message 属性名
       * @param {any} updateContentz 默认属性值
       */
      _fireUpdateEvent(message, updateContent) {
        if (!this._map) return
        this._map.fire(
          LayerEventType.layerUpdate,
          new LayerViewUpdateEvent({
            type: LayerEventType.layerUpdate,
            target: this._map,
            layer: this,
            message,
            updateContent
          })
        )
      }

      /**
       * @description 转换为json对象
       * @return {Object} json对象
       */
      toJSON() {
        return {
          id: this.id,
          description: this.description,
          copyright: this.copyright,
          loadStatus: this.loadStatus,
          loaded: this.loaded,
          tokenKey: this.tokenKey,
          tokenValue: this.tokenValue,
          index: this.index,
          title: this.title,
          minScale: this.minScale,
          maxScale: this.maxScale,
          type: this.type,
          visible: this.visible,
          opacity: this.opacity,
          spatialReference: toJSON(this.spatialReference, SpatialReference),
          extent: toJSON(this.extent, Extent)
        }
      }

      /**
       * @description 克隆方法
       * @return {Layer} 图层
       */
      clone() {
        return new Layer(this.toJSON())
      }

      /**
       * @description 根据服务url加载图层(通过判断url链接获取图层,等图层全部封装完毕后处理此函数)
       * @param {String} url 服务地址
       * @param {Object} options 图层配置
       * @return {Promise<Layer>} 从url中加载图层
       */
      static fromServerUrl(url, options) {
        return new Promise((reslove) => {
          options.url = url
          reslove(new Layer(options))
        })
      }

      /**
       * 刷新图层
       * */
      refresh() {
        this._fireUpdateEvent('刷新图层', [
          {
            params: arguments,
            dataChanged: true,
            name: 'refresh',
            operationType: 'method'
          }
        ])
      }

      /**
       * 更新图层顺序
       * @private
       * */
      _updateIndex() {
        this._fireUpdateEvent('修改图层的index', [
          {
            name: 'index',
            params: [this],
            dataChanged: true,
            operationType: 'property'
          }
        ])
      }
    }

    Object.defineProperties(Layer.prototype, {
      /**
       * 图层显示或隐藏，true则显示，false则隐藏，会触发图层更新完毕事件
       * @member Layer.prototype.visible
       * @type {Number}
       */
      visible: {
        get() {
          return this._visible
        },
        set(value) {
          this._visible = value
          this._fireUpdateEvent('显隐变化', [
            {
              name: 'visible',
              params: [this._visible],
              dataChanged: true,
              operationType: 'property'
            }
          ])
        }
      },
      /**
       * 图层透明度，0到1之间的值，0为完全透明，1为不透明，会触发图层更新完毕事件
       * @member Layer.prototype.opacity
       * @type {Number}
       */
      opacity: {
        get() {
          return this._opacity
        },
        set(value) {
          this._opacity = Number(value)
          this._fireUpdateEvent('透明度变化', [
            {
              name: 'opacity',
              params: [this._opacity],
              dataChanged: true,
              operationType: 'property'
            }
          ])
        }
      },
      /**
       * 图层坐标系对象
       * @member Layer.prototype.spatialReference
       * @type {SpatialReference}
       */
      spatialReference: {
        get() {
          return this._spatialReference
        },
        set(value) {
          this._spatialReference = value
        }
      },
      /**
       * 图层范围，从服务元信息中获取
       * @readonly
       * @member {Extent} Layer.prototype.extent
       */
      extent: {
        get() {
          return this._extentSrc
        },
        set(value) {
          this._extentSrc = value
        }
      }
    })

    Zondy.Layer.Layer = Layer
    export default Layer