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

/**
 * 定义 MapGIS Common API IGS要素图层类
 *
 * @alias IGSFeatureLayer
 *
 * @summary <用于加载和管理IGS要素服务图层，支持IGS1.0、2.0以及GDBP服务>
 * @description 该类负责具体的图层操作逻辑，包括图层的加载、显示/隐藏、移除等。
 *              底层通过 zondy.layer.IGSFeatureLayer 与 Mapbox GL JS 进行交互。
 */
export default class IGSFeatureLayer {
    /**
     * 构造函数
     * @param {Object} options - 图层配置选项
     * @param {Object} options.map - 地图对象（mapboxgl.Map 实例）
     * @param {String} options.url - 服务基地址
     * @param {Number|String} [options.sublayerId=0] - 要素服务的子图层id
     * @param {String} [options.gdbp=''] - gdbp数据源
     * @param {String} [options.id] - 图层ID（可选，不传则自动生成）
     * @param {String} [options.title=''] - 图层标题
     * @param {String} [options.description=''] - 图层描述
     * @param {Number} [options.opacity=1] - 图层透明度 (0-1)
     * @param {Boolean} [options.visible=true] - 图层可见性
     * @param {String} [options.renderMode='client'] - 渲染模式 ('client'|'server'|'grid')
     * @param {Object} [options.timeExtent=null] - 时间范围
     * @param {Object} [options.timeInfo=null] - 时间维度信息描述
     * @param {Object} [options.renderer=null] - 渲染样式
     * @param {String} [options.definitionExpression=''] - SQL语句查询条件
     * @param {Object} [options.serverFilter=null] - 服务端要素过滤选项
     * @param {Array<String>} [options.outFields=null] - 返回要素字段列表
     * @param {Boolean} [options.labelsVisible=false] - 是否开启动态注记（仅支持三维场景）
     * @param {Array<Object>} [options.labelingInfo=[]] - 注记样式数组（仅支持三维场景）
     * @param {Number} [options.minScale=0] - 最小显示比例尺
     * @param {Number} [options.maxScale=0] - 最大显示比例尺
     * @param {String} [options.tokenKey='token'] - Token键名
     * @param {String} [options.tokenValue=''] - Token值
     * @param {Boolean} [options.supportArc3=true] - 是否返回三点弧段数据
     * @param {Object} [options.elevationInfo=null] - 高程模式参数
     */
    constructor(options) {
        /**
         * 地图对象
         * @type {Object}
         */
        this._map = options.map;

        /**
         * 底层 zondy.layer.IGSFeatureLayer 实例
         * @type {Object|null}
         */
        this._layer = null;

        /**
         * 服务基地址
         * 支持的服务如下：
         * 1. IGS2.0服务：http://{ip}:{port}/igs/rest/services/{folder}/{ServiceName}/FeatureServer
         * 2. IGS1.0服务：http://{ip}:{port}/igs/rest/mrfs/docs/{folder}:{ServiceName}
         * 3. GDBP服务：http://{ip}:{port}/igs/rest/mrfs/layer
         * @type {String}
         */
        this._url = options.url;

        /**
         * 要素服务的子图层id
         * 不指定子图层ID则查询第0个子图层，指定时则查询指定sublayerId的子图层
         * 仅支持单图层的要素查询，不支持多图层和子图层的要素查询
         * @type {Number|String}
         */
        this._sublayerId = DataUtils.default(options.sublayerId, 0);

        /**
         * gdbp数据源
         * 指定一个gdbp数据源来加载图形，格式如下：
         * gdbp://MapGisLocal/武汉市/ds/4326矢量/sfcls/武汉市区划4326
         * @type {String}
         */
        this._gdbp = DataUtils.default(options.gdbp, '');

        /**
         * 图层ID
         * @type {String}
         */
        this._layerId = DataUtils.default(options.id, 'igs_feature_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 {String}
         */
        this._title = DataUtils.default(options.title, '');

        /**
         * 图层描述
         * @type {String}
         */
        this._description = DataUtils.default(options.description, '');

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

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

        /**
         * 渲染模式
         * 支持客户端渲染'client'、服务器端渲染'server'(不支持renderer)、网格化渲染'grid'（目前仅支持cesium引擎）
         * 目前仅当gdbp存在时，server模式生效
         * 设置renderer时不支持聚类渲染器以及热力图渲染器
         * @type {String}
         */
        this._renderMode = DataUtils.default(options.renderMode, 'client');

        /**
         * 时间范围
         * 具有明确开始和结束日期的一段时间（目前仅支持renderMode为'grid'时生效）
         * 时间范围用于显示或查询指定时间段内的要素
         * 要表示某个时刻，需要将开始时间和结束时间设置为同一日期
         * @type {Object|null}
         */
        this._timeExtent = options.timeExtent || null;

        /**
         * 对于数据时间维度信息的描述（目前仅支持renderMode为'grid'时生效）
         * @type {Object|null}
         */
        this._timeInfo = options.timeInfo || null;

        /**
         * 渲染样式
         * 目前支持如下样式：
         * 1. UniqueValueRenderer - 单值专题图
         * 2. ClassBreakRenderer - 分段专题图
         * 3. SimpleRenderer - 统一专题图
         * @type {Object|null}
         */
        this._renderer = options.renderer || null;

        /**
         * sql语句查询，例如 name ='wuhan'
         * 优先级要高于serverFilter选项
         * @type {String}
         */
        this._definitionExpression = DataUtils.default(options.definitionExpression, '');

        /**
         * 服务端要素过滤选项
         * @type {Object|null}
         */
        this._serverFilter = options.serverFilter || null;

        /**
         * 服务器请求返回要素时，要素中包含的字段列表
         * 默认为null，表示请求返回的要素中包含全字段
         * 筛选要素字段可以通过数组传递，例如["NAME", "GDP2016", "GDP2017", "GDP2018"]
         * @type {Array<String>|null}
         */
        this._outFields = options.outFields || null;

        /**
         * 是否开启动态注记，仅支持三维场景
         * @type {Boolean}
         */
        this._labelsVisible = DataUtils.default(options.labelsVisible, false);

        /**
         * 注记样式数组，可以和renderer同时启用，默认取数组的第一个样式
         * 仅支持三维场景
         * @type {Array<Object>}
         */
        this._labelingInfo = DataUtils.default(options.labelingInfo, []);

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

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

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

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

        /**
         * 是否返回三点弧段数据
         * 为true则返回三个点代表三点弧段，否则返回离散的点
         * @type {Boolean}
         */
        this._supportArc3 = DataUtils.default(options.supportArc3, true);

        /**
         * 高程模式参数
         * @type {Object|null}
         */
        this._elevationInfo = options.elevationInfo || null;

        /**
         * 图层类型
         * @type {String}
         */
        this._type = 'igs-feature';

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

        this._isFlyTo = DataUtils.default(options.isFlyTo, false);
    }

    _buildOptions() {
        const options = {
            url: this._url,
            type: this._type,
            sublayerId: this._sublayerId,
            id: this._layerId,
            opacity: this._opacity,
            visible: this._visible,
            renderMode: this._renderMode,
            renderer: this._renderer,
            definitionExpression: this._definitionExpression,
            serverFilter: this._serverFilter,
            outFields: this._outFields,
            labelsVisible: this._labelsVisible,
            labelingInfo: this._labelingInfo,
            minScale: this._minScale,
            maxScale: this._maxScale,
            tokenKey: this._tokenKey,
            tokenValue: this._tokenValue,
            supportArc3: this._supportArc3
        };

        // 可选参数
        if (this._gdbp) {
            options.gdbp = this._gdbp;
        }

        if (this._timeExtent) {
            options.timeExtent = this._timeExtent;
        }

        if (this._timeInfo) {
            options.timeInfo = this._timeInfo;
        }

        if (this._elevationInfo) {
            options.elevationInfo = this._elevationInfo;
        }

        return options;
    }

    /** ==================== Core Methods ==================== */

    /**
     * 加载图层资源
     * @description 不加载图层到地图，仅获取图层信息
     * @param {Function} [onLoaded] - 可选的回调函数，在图层加载完成后执行
     * @returns {Promise<IGSFeatureLayer>} 返回图层实例的 Promise
     *
     * @example
     * const layer = new IGSFeatureLayer({
     *     url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/FeatureServer'
     * });
     * layer.load().then((result) => {
     *     console.log(result); // 获取完图层信息
     * });
     */
    load(onLoaded) {
        return new Promise((resolve, reject) => {
            try {
                if (!this._layer) {
                    const opts = this._buildOptions();
                    this._layer = new zondy.layer.IGSFeatureLayer(opts);
                }

                // 监听图层加载完成事件
                const handler = (result) => {
                    // 移除事件监听器
                    this._layer.off('layerview-created', handler);

                    // 如果提供了回调函数，执行它
                    if (onLoaded && typeof onLoaded === 'function') {
                        onLoaded(result);
                    }

                    resolve(this);
                };

                this._layer.on('layerview-created', handler);

                // 如果已经加载完成，直接返回
                if (this._layer.loadStatus === 'loaded') {
                    // 如果提供了回调函数，也需要执行
                    if (onLoaded && typeof onLoaded === 'function') {
                        onLoaded({ layer: this._layer });
                    }
                    resolve(this);
                }
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * 加载图层到地图
     * @description 调用 zondy.layer.IGSFeatureLayer 加载图层数据，并添加到 Mapbox GL 地图中
     * @returns {Promise<void>}
     *
     * @example
     * const layer = new IGSFeatureLayer({
     *     map: mapboxMap,
     *     url: 'http://xxx/igs/rest/services/Map/图层/FeatureServer'
     * });
     * await layer.loadLayer();
     */
    loadLayer() {
        if (this.hasLayer()) return;

        const opts = this._buildOptions();

        // 创建 zondy.layer.IGSFeatureLayer 实例
        const layer = new zondy.layer.IGSFeatureLayer(opts);
        this._layer = layer;
        // 将图层添加到 MapGIS 地图对象
        this.addToMapGisMap();
        // 监听图层加载完成事件
        layer.on('layerview-created',(result) => {
            //视点跳转
            this._isFlyTo && gisView.goTo({
                layer: result.layer
            })
        });
    }

    /**
     * 将图层添加到 MapGIS 地图
     */
    addToMapGisMap() {
        this._map.add(this._layer)
    }

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

    /**
     * 判断图层是否已加载
     *
     * @returns {Boolean}
     */
    hasLayer() {
        // 优先检查底层 zondy.layer.IGSFeatureLayer 的加载状态
        if (this._layer && this._layer.loadStatus === 'loaded') {
            return true;
        }
        return false;
    }

    /**
     * 移除图层
     */
    removeLayer() {
        // 移除底层 zondy.layer.IGSFeatureLayer
        if (this._layer) {
            this._layer.remove();
            this._layer = null;
        }

        // 从管理器中移除
        removeLayerFromManager(this);
    }

    /**
     * 指定图层的要素查询
     * @param {Object} queryOptions - 查询选项
     * @param {String|Number} [queryOptions.layerId] - 图层id
     * @param {String} [queryOptions.where] - where语句，例如 "NAME='天门市'"
     * @param {Array<String>} [queryOptions.outFields] - 输出字段列表
     * @param {Boolean} [queryOptions.returnGeometry=true] - 是否返回几何信息
     * @param {Object} [queryOptions.geometry] - 空间查询几何对象
     * @param {String} [queryOptions.spatialRel] - 空间关系类型
     * @param {Number} [queryOptions.maxFeatures] - 最大返回要素数量
     * @returns {Promise<Object>} 返回 FeatureSet 对象的 Promise
     *
     * @example
     * layer.queryFeatures({
     *     layerId: '0',
     *     where: "NAME='天门市'"
     * }).then((result) => {
     *     console.log('查询结果:', result);
     * });
     */
    queryFeatures(queryOptions) {
        return new Promise((resolve, reject) => {
            if (!this._layer) {
                reject(new Error('图层未加载，请先调用 load() 或 loadLayer()'));
                return;
            }

            try {
                // 调用底层图层的 queryFeatures 方法
                this._layer.queryFeatures(queryOptions).then((result) => {
                    resolve(result);
                }).catch((error) => {
                    reject(error);
                });
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * 查询要素数量
     * @param {Object} queryOptions - 查询选项
     * @param {String|Number} [queryOptions.layerId] - 图层id
     * @param {String} [queryOptions.where] - where语句
     * @param {Object} [queryOptions.geometry] - 空间查询几何对象
     * @param {String} [queryOptions.spatialRel] - 空间关系类型
     * @returns {Promise<Number>} 返回要素数量的 Promise
     *
     * @example
     * layer.queryFeaturesCount({
     *     layerId: '0'
     * }).then((result) => {
     *     console.log('查询结果:', result);
     * });
     */
    queryFeaturesCount(queryOptions) {
        return new Promise((resolve, reject) => {
            if (!this._layer) {
                reject(new Error('图层未加载，请先调用 load() 或 loadLayer()'));
                return;
            }

            try {
                // 调用底层图层的 queryFeaturesCount 方法
                this._layer.queryFeaturesCount(queryOptions).then((result) => {
                    resolve(result);
                }).catch((error) => {
                    reject(error);
                });
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * 转换为 JSON 对象
     * @returns {Object} JSON 对象
     *
     * @example
     * const json = layer.toJSON();
     * console.log(json);
     */
    toJSON() {
        return {
            url: this._url,
            sublayerId: this._sublayerId,
            gdbp: this._gdbp,
            id: this._layerId,
            title: this._title,
            description: this._description,
            opacity: this._opacity,
            visible: this._visible,
            renderMode: this._renderMode,
            timeExtent: this._timeExtent,
            timeInfo: this._timeInfo,
            renderer: this._renderer ? this._renderer.toJSON ? this._renderer.toJSON() : this._renderer : null,
            definitionExpression: this._definitionExpression,
            serverFilter: this._serverFilter,
            outFields: this._outFields,
            labelsVisible: this._labelsVisible,
            labelingInfo: this._labelingInfo,
            minScale: this._minScale,
            maxScale: this._maxScale,
            tokenKey: this._tokenKey,
            tokenValue: this._tokenValue,
            supportArc3: this._supportArc3,
            elevationInfo: this._elevationInfo,
            type: this._type
        };
    }

    /**
     * 克隆 IGSFeatureLayer 对象
     * @returns {IGSFeatureLayer} 克隆后的 IGSFeatureLayer 实例
     *
     * @example
     * const clonedLayer = layer.clone();
     */
    clone() {
        const json = this.toJSON();
        return IGSFeatureLayer.fromJSON(json);
    }

    /**
     * 通过传入的 JSON 构造并返回一个新的 IGSFeatureLayer 实例
     * @static
     * @param {Object} json - JSON 对象
     * @returns {IGSFeatureLayer} 新的 IGSFeatureLayer 实例
     *
     * @example
     * const json = {
     *     url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/FeatureServer'
     * };
     * const layer = IGSFeatureLayer.fromJSON(json);
     */
    static fromJSON(json) {
        if (!json || !json.url) {
            throw new Error('JSON 对象必须包含 url 属性');
        }

        return new IGSFeatureLayer({
            url: json.url,
            sublayerId: json.sublayerId,
            gdbp: json.gdbp,
            id: json.id,
            title: json.title,
            description: json.description,
            opacity: json.opacity,
            visible: json.visible,
            renderMode: json.renderMode,
            timeExtent: json.timeExtent,
            timeInfo: json.timeInfo,
            renderer: json.renderer,
            definitionExpression: json.definitionExpression,
            serverFilter: json.serverFilter,
            outFields: json.outFields,
            labelsVisible: json.labelsVisible,
            labelingInfo: json.labelingInfo,
            minScale: json.minScale,
            maxScale: json.maxScale,
            tokenKey: json.tokenKey,
            tokenValue: json.tokenValue,
            supportArc3: json.supportArc3,
            elevationInfo: json.elevationInfo
        });
    }

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

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

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

    /**
     * 获取子图层ID
     * @returns {Number|String}
     */
    get sublayerId() {
        return this._sublayerId;
    }

    /**
     * 获取gdbp数据源
     * @returns {String}
     */
    get gdbp() {
        return this._gdbp;
    }

    /**
     * 获取图层类型
     * @returns {String}
     */
    get type() {
        return this._type;
    }

    /**
     * 获取渲染模式
     * @returns {String}
     */
    get renderMode() {
        return this._renderMode;
    }

    /**
     * 获取渲染器
     * @returns {Object|null}
     */
    get renderer() {
        return this._renderer;
    }

    /**
     * 获取要素过滤条件
     * @returns {String}
     */
    get definitionExpression() {
        return this._definitionExpression;
    }

    /**
     * 获取服务端过滤选项
     * @returns {Object|null}
     */
    get serverFilter() {
        return this._serverFilter;
    }

    /**
     * 获取输出字段列表
     * @returns {Array<String>|null}
     */
    get outFields() {
        return this._outFields;
    }

    /**
     * 获取是否开启动态注记
     * @returns {Boolean}
     */
    get labelsVisible() {
        return this._labelsVisible;
    }

    /**
     * 获取注记样式数组
     * @returns {Array<Object>}
     */
    get labelingInfo() {
        return this._labelingInfo;
    }

    /**
     * 获取最小显示比例尺
     * @returns {Number}
     */
    get minScale() {
        return this._minScale;
    }

    /**
     * 获取最大显示比例尺
     * @returns {Number}
     */
    get maxScale() {
        return this._maxScale;
    }

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

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

    /**
     * 获取时间范围
     * @returns {Object|null}
     */
    get timeExtent() {
        return this._timeExtent;
    }

    /**
     * 获取时间信息
     * @returns {Object|null}
     */
    get timeInfo() {
        return this._timeInfo;
    }

    /**
     * 获取高程模式参数
     * @returns {Object|null}
     */
    get elevationInfo() {
        return this._elevationInfo;
    }

    /**
     * 获取是否返回三点弧段数据
     * @returns {Boolean}
     */
    get supportArc3() {
        return this._supportArc3;
    }

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

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

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

    /**
     * 设置可见性
     * @param {Boolean} value - 是否可见
     */
    set visible(value) {
        this._visible = value;
        if (this._layer) {
            this._layer.visible = value;
        }
    }

    /**
     * 设置渲染器
     * @param {Object} value - 渲染器对象
     */
    set renderer(value) {
        this._renderer = value;
        if (this._layer) {
            this._layer.renderer = value;
        }
    }

    /**
     * 设置要素过滤条件
     * @param {String} value - SQL语句
     */
    set definitionExpression(value) {
        this._definitionExpression = value;
        if (this._layer) {
            this._layer.definitionExpression = value;
        }
    }

    /**
     * 设置是否开启动态注记
     * @param {Boolean} value - 是否开启
     */
    set labelsVisible(value) {
        this._labelsVisible = value;
        if (this._layer) {
            this._layer.labelsVisible = value;
        }
    }

    /** ==================== Event Methods ==================== */

    /**
     * 注册事件监听器
     * @param {String} eventName - 事件名称
     * @param {Function} callback - 回调函数
     */
    on(eventName, callback) {
        if (!this._eventListeners[eventName]) {
            this._eventListeners[eventName] = [];
        }
        this._eventListeners[eventName].push(callback);
    }

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

        const index = this._eventListeners[eventName].indexOf(callback);
        if (index > -1) {
            this._eventListeners[eventName].splice(index, 1);
        }
    }

    /**
     * 触发事件
     * @param {String} eventName - 事件名称
     * @param {*} data - 事件数据
     * @private
     */
    _emit(eventName, data) {
        if (!this._eventListeners[eventName]) return;

        this._eventListeners[eventName].forEach(callback => {
            try {
                callback(data);
            } catch (error) {
                console.error(`Event handler error for ${eventName}:`, error);
            }
        });
    }
}
