import DataUtils from '../../../../mapboxgl/js/utils/DataUtils';
import {removeLayerFromManager} from "../";

/**
 * 定义 MapGIS Common API IGS矢量瓦片图层类
 *
 * @alias IGSVectorTileLayer
 *
 * @summary <用于加载和管理IGS矢量瓦片服务图层，支持IGS1.0和2.0两个服务版本>
 * @description 该类负责具体的图层操作逻辑，包括图层的加载、显示/隐藏、移除等。
 */
export default class IGSVectorTileLayer {
    /**
     * 构造函数
     * @param {Object} options - 图层选项
     */
    constructor(options) {
        /**
         * 视图对象
         * @type {Object}
         */
        this._view = options.view;

        this._layer = null

        /**
         * 服务基地址，和style参数二者选其一
         * IGS1.0的服务基地址为：http://{ip}:6163/igs/rest/mrcs/vtiles/{folder}:{serviceName}
         * IGS2.0的服务基地址为：http://{ip}:{port}/igs/rest/services/{folder}/{serviceName}/VectorTileServer
         * 样式文件地址：http://{文件服务路径}/{样式文件名称}.json
         * @type {String}
         */
        this._url = options.url || null;

        /**
         * 图层ID
         * @type {String}
         */
        this._layerId = DataUtils.default(options.id + '_source', 'igs_vector_tile_layer_' + new Date().getTime());

        /**
         * mapboxgl Map 下的实际图层ID
         * @type {string}
         * @private
         */
        this._mapboxLayerId = 'layer_' + this._layerId

        /**
         * 数据源ID
         * @type {String}
         */
        this._sourceId = this._layerId;

        /**
         * mapboxgl Map 下的实际sourceID
         * @type {string}
         * @private
         */
        this._mapboxSourceId = 'source_' + this._layerId;

        /**
         * 子图层列表对象
         * 会通过该参数中指定的子图层列表对矢量瓦片服务中的子图层进行过滤
         * 不在列表中的子图层将不会显示；如果没有指定该参数，则会按照矢量瓦片服务中的子图层的属性显示所有子图层
         * 如果该参数为空数组，则矢量瓦片服务所有的子图层都不显示
         * @type {Array}
         */
        this._sublayers = DataUtils.default(options.sublayers, []);

        /**
         * 最小显示比例尺，图层在视图中可见的最小比例尺
         * @type {Number}
         */
        this._minScale = DataUtils.default(options.minScale, 0);

        /**
         * 最大显示比例尺，图层在视图中可见的最大比例尺
         * @type {Number}
         */
        this._maxScale = DataUtils.default(options.maxScale, 0);

        /**
         * 图层透明度 (0-1)，0为完全透明，1为不透明
         * @type {Number}
         */
        this._opacity = DataUtils.default(options.opacity, 1);

        /**
         * Token键名
         * @type {String}
         */
        this._tokenKey = DataUtils.default(options.tokenKey, 'token');

        /**
         * Token值，只有当tokenValue存在时，才会绑定token
         * @type {String}
         */
        this._tokenValue = DataUtils.default(options.tokenValue, '');

        /**
         * 图层显示或隐藏，true则显示，false则隐藏
         * @type {Boolean}
         */
        this._visible = DataUtils.default(options.visible, true);

        /**
         * 指定矢量瓦片注记的渲染模式，仅在三维上有效
         * on-screen: 使用Cesium接口实时渲染注记
         * off-screen: 使用矢量瓦片来绘制注记
         * @type {String}
         */
        this._labelsRenderMode = DataUtils.default(options.labelsRenderMode, 'off-screen');

        /**
         * 图层空间裁剪范围，仅支持多多边形裁剪、多边形裁剪、矩形裁剪、圆形裁剪
         * @type {Object|null}
         */
        this._clippingArea = DataUtils.default(options.clippingArea, null);

        /**
         * 初始化图层时，是否将样式中的基地址替换为图层的基地址
         * @type {Boolean}
         */
        this._replaceStyleURL = DataUtils.default(options.replaceStyleURL, true);

        /**
         * 当replaceStyleURL设置为true时，将样式中的基地址替换为图层的基地址操作中使用的正则表达式
         * @type {RegExp}
         */
        this._replaceStyleURLRegExp = options.replaceStyleURLRegExp || null;

        /**
         * mvt矢量瓦片相对坐标范围，默认为4096，表示矢量瓦片相对坐标的范围为0到4096
         * @type {Number}
         */
        this._mvtExtent = DataUtils.default(options.mvtExtent, 4096);

        /**
         * 当前的矢量瓦片样式信息，包含serviceUrl 、styleUrl 、spriteUrl 、glyphsUrl 以及style
         * @type {Object}
         */
        this._currentStyleInfo = options.currentStyleInfo || {};

        /**
         * 图层描述
         * @type {String}
         */
        this._description = options.description || 'IGS矢量瓦片图层';

        /**
         * 图层标题
         * @type {String}
         */
        this._title = options.title || '';

        this._style = options.style || null;

        /**
         * 当瓦片图层的显示比例尺范围，超出瓦片数据自身的级别后的显示策略
         * @type {Object|null}
         */
        this._tileDisplayStrategy = options.tileDisplayStrategy || null;

        /**
         * 瓦片切图信息
         * @type {Object|null}
         */
        this._tileInfo = options.tileInfo || null;

        /**
         * 所有子图层对象信息
         * @type {Array}
         */
        this._allSublayers = [];

        /**
         * 图层类型
         * @type {String}
         */
        this._type = options.type || 'igs-vector-tile';

        /**
         * 事件监听器集合
         * @type {Object}
         */
        this._eventListeners = {};
    }

    _buildOptions() {
        const options = {
            url: this._url,
            id: this._layerId,
            type: this._type,
            sublayers: this._sublayers,
            minScale: this._minScale,
            maxScale: this._maxScale,
            opacity: this._opacity,
            tokenKey: this._tokenKey,
            tokenValue: this._tokenValue,
            visible: this._visible,
            labelsRenderMode: this._labelsRenderMode,
            replaceStyleURL: this._replaceStyleURL,
            mvtExtent: this._mvtExtent,
            description: this._description,
            title: this._title
        };

        // 如果指定了替换样式URL的正则表达式，添加到选项中
        if (this._replaceStyleURLRegExp) {
            options.replaceStyleURLRegExp = this._replaceStyleURLRegExp;
        }

        // 如果指定了瓦片显示策略，添加到选项中
        if (this._tileDisplayStrategy) {
            options.tileDisplayStrategy = this._tileDisplayStrategy;
        }

        // 如果指定了瓦片切图信息，添加到选项中
        if (this._tileInfo) {
            options.tileInfo = this._tileInfo;
        }

        if (this._style) {
            options.style = this._style;
        }

        if (this._clippingArea) {
            options.clippingArea = this._clippingArea;
        }

        return options;
    }

    /**
     * 加载图层到地图
     * @description 调用 zondy.layer.IGSVectorTileLayer 加载图层数据,并添加到 Mapbox GL 地图中
     * @returns {Promise<void>}
     *
     * @example
     * // IGS2.0 VectorTileServer方式
     * const layer = new IGSVectorTileLayer({
     *     map: mapboxMap,
     *     url: 'http://xxx/igs/rest/services/VectorTile/图层名称/VectorTileServer'
     * });
     *
     * // IGS1.0 VectorTileServer方式(需要指定坐标系)
     * const layer = new IGSVectorTileLayer({
     *     map: mapboxMap,
     *     url: 'http://xxx:6163/igs/rest/mrcs/vtiles/图层名称',
     *     spatialReference: new SpatialReference({ wkid: 4326 })
     * });
     *
     * // JSON样式文件方式
     * const layer = new IGSVectorTileLayer({
     *     map: mapboxMap,
     *     url: 'http://xxx/图层样式.json'
     * });
     *
     * // Style对象方式
     * FetchRequest.commit('get', 'http://xxx/图层样式.json', {}).then((result) => {
     *     return result.json().then((styleJSON) => {
     *         const layer = new IGSVectorTileLayer({
     *             map: mapboxMap,
     *             style: styleJSON
     *         });
     *         await layer.loadLayer();
     *     });
     * });
     *
     * await layer.loadLayer();
     */
    loadLayer() {
        if (this.hasLayer()) return;
        const layer = new zondy.layer.IGSVectorTileLayer(this._buildOptions())
        this._layer = layer;
        layer.load().then(() => {
            // 添加到mapboxgl地图对象中
            this.addToMapGisMap(MapgisMap, layer)

            // 触发自定义事件
            this._emitEvent('layerview-created', {layer: this._layer});
        });
    }

    addToMapGisMap(map, layer) {
        if (layer) {
            map.add(layer)
        }
    }

    /**
     * 根据子图层id查询图层
     * @param {String|Number} sublayerID - 子图层ID
     * @returns {Object|null} 子图层对象或null
     */
    findSublayerById(sublayerID) {
        if (!this._layer) {
            console.warn('IGS矢量瓦片图层未加载');
            return null;
        }

        return this._layer.findSublayerById(sublayerID);
    }

    /**
     * 显示/隐藏图层
     * @param {Boolean} isShow - 是否显示图层(true: 显示,false: 隐藏)
     */
    showLayer(isShow) {
        this._layer.visible = isShow;
        this._visible = isShow;
    }

    /**
     * 显隐子图层
     * @param {String} sublayerId - 子图层ID
     * @description 切换指定子图层的可见性
     *
     * @example
     * layer.setSubLayerVisible('湖北省市级区划_simplerender');
     */
    setSubLayerVisible(sublayerId) {
        if (!this._layer) {
            console.warn('IGS矢量瓦片图层未加载');
            return;
        }

        const layout = this.getLayoutProperties(sublayerId);
        if (layout && layout.visibility) {
            const newVisibility = layout.visibility === 'visible' ? 'none' : 'visible';
            this.setLayoutProperties(sublayerId, {
                visibility: newVisibility
            });
        }
    }

    /**
     * 判断图层是否已加载
     *
     * @returns {Boolean}
     */
    hasLayer() {
        return !!MapgisMap.findLayerById(this._layerId);
    }

    getLayerById() {
        return MapgisMap.findLayerById(this._layerId)
    }

    /**
     * 获取子图层的布局属性
     * @param {String} sublayerId - 子图层ID
     * @returns {Object|null} 布局属性对象或null
     *
     * @example
     * const layout = layer.getLayoutProperties('湖北省市级区划_simplerender');
     * console.log(layout.visibility);
     */
    getLayoutProperties(sublayerId) {
        if (!this._layer) {
            console.warn('IGS矢量瓦片图层未加载');
            return null;
        }

        return this._layer.getLayoutProperties(sublayerId);
    }

    /**
     * 设置子图层的布局属性
     * @param {String} sublayerId - 子图层ID
     * @param {Object} properties - 布局属性对象
     * @description 和MapboxGL的矢量瓦片参数一致
     *
     * @example
     * layer.setLayoutProperties('湖北省市级区划_simplerender', {
     *     visibility: 'none'  // 或 'visible'
     * });
     */
    setLayoutProperties(sublayerId, properties) {
        if (!this._layer) {
            console.warn('IGS矢量瓦片图层未加载');
            return;
        }

        this._layer.setLayoutProperties(sublayerId, properties);
    }

    /**
     * 设置子图层的绘制属性
     * @param {String} sublayerId - 子图层ID
     * @param {Object} properties - 绘制属性对象
     * @description 和MapboxGL的矢量瓦片参数一致
     *
     * @example
     * layer.setPaintProperties('湖北省市级区划_simplerender', {
     *     'fill-color': 'rgba(11,178,97,1.000000)'
     * });
     */
    setPaintProperties(sublayerId, properties) {
        if (!this._layer) {
            console.warn('IGS矢量瓦片图层未加载');
            return;
        }

        this._layer.setPaintProperties(sublayerId, properties);
    }

    /**
     * 获取子图层的绘制属性
     * @param {String} sublayerId - 子图层ID
     * @returns {Object|null} 绘制属性对象或null
     *
     * @example
     * const paint = layer.getPaintProperties('湖北省市级区划_simplerender');
     * console.log(paint['fill-color']);
     */
    getPaintProperties(sublayerId) {
        if (!this._layer) {
            console.warn('IGS矢量瓦片图层未加载');
            return null;
        }

        return this._layer.getPaintProperties(sublayerId);
    }

    /**
     * 移除图层
     */
    removeLayer() {
        MapgisMap.remove(this._layer);
        removeLayerFromManager(this._layer)
        this._layer = null;
    }

    /**
     * 移除数据源
     */
    removeSource() {
        // LayerProvider.removeSource(MapgisMap, this._mapboxSourceId);
    }

    /** ==================== 事件管理 ==================== */

    /**
     * 注册事件监听器
     * @param {String} eventName - 事件名称
     * @param {Function} callback - 回调函数
     *
     * @example
     * layer.on('layerview-created', (result) => {
     *     console.log('图层创建完成', result.layer);
     * });
     */
    on(eventName, callback) {
        if (!this._eventListeners) {
            this._eventListeners = {};
        }
        if (!this._eventListeners[eventName]) {
            this._eventListeners[eventName] = [];
        }
        this._eventListeners[eventName].push(callback);

        // 如果图层实例已存在,也注册到实例上
        if (this._layer && this._layer.on) {
            this._layer.on(eventName, callback);
        }
    }

    /**
     * 移除事件监听器
     * @param {String} eventName - 事件名称
     * @param {Function} callback - 回调函数
     */
    off(eventName, callback) {
        if (this._eventListeners && this._eventListeners[eventName]) {
            this._eventListeners[eventName] = this._eventListeners[eventName].filter(
                    cb => cb !== callback
            );
        }

        // 如果图层实例已存在,也从实例上移除
        if (this._layer && this._layer.off && callback) {
            this._layer.off(eventName, callback);
        }
    }

    /**
     * 触发事件
     * @private
     * @param {String} eventName - 事件名称
     * @param {Object} data - 事件数据
     */
    _emitEvent(eventName, data) {
        if (this._eventListeners && this._eventListeners[eventName]) {
            this._eventListeners[eventName].forEach(callback => {
                try {
                    callback(data);
                } catch (error) {
                    console.error(`事件 ${eventName} 回调执行错误:`, error);
                }
            });
        }
    }

    /** ==================== Getter/Setter ==================== */

    /**
     * 获取图层ID
     * @returns {String}
     */
    get id() {
        return this._layerId;
    }

    /**
     * 获取服务URL
     * @returns {String}
     */
    get url() {
        return this._url;
    }

    /**
     * 获取所有子图层
     * @returns {Array}
     */
    get allSublayers() {
        return this._allSublayers;
    }

    /**
     * 获取图层实例
     * @returns {Object}
     */
    get instance() {
        return this._layer;
    }

    /**
     * 获取图层透明度
     * @returns {Number}
     */
    get opacity() {
        return this._opacity;
    }

    /**
     * 设置图层透明度
     * @param {Number} value - 透明度值(0-1)
     */
    set opacity(value) {
        this._opacity = value;
        if (this._layer) {
            this._layer.opacity = value;
        }
    }

    /**
     * 获取图层可见性
     * @returns {Boolean}
     */
    get visible() {
        return this._visible;
    }

    /**
     * 设置图层可见性
     * @param {Boolean} value - 可见性
     */
    set visible(value) {
        this._visible = value;
        if (this._layer) {
            this._layer.visible = value;
        }
        // 同步更新MapboxGL图层的可见性
        if (MapgisMap) {
            this.showLayer(value);
        }
    }
}
