/**
 * sup 上报底层脚本 - 设备标识 & 批量埋点上报
 * 使用方式：import supersetLewo from './superset-lewo';
 */

// 兼容 globalThis 缺失的环境
if (typeof (globalThis as any) === 'undefined') {
    if (typeof (self as any) !== 'undefined') (self as any).globalThis = self;
    else if (typeof (window as any) !== 'undefined') (window as any).globalThis = window;
}

// 全局类型声明（aplus 友盟上报队列）
declare const aplus_queue: any;

export interface ISupersetUserInfo {
    os_type?: string;
    os_version?: string;
    app_version?: string;
    app_item?: string;
    app_name?: string;
    app_project?: string;
    province?: string;
    city?: string;
    uid?: string;
    user_id?: string;
    device_brand?: string;
    device_model?: string;
    network_type?: string;
    carrier?: string;
    device_id?: string;
    promotion_flag?: string;
    user_type?: string;
}

export interface ISupersetReportItem {
    [key: string]: any;
}

export interface ISupersetAjaxConfig {
    url: string;
    data: any;
    async?: boolean;
    type?: string;
    contentType?: string;
    dataType?: string;
    headers?: Array<{ name: string; value: string }>;
    success?: (xhr: XMLHttpRequest, rsp: any) => void;
    error?: (xhr: XMLHttpRequest | null, rsp: any) => void;
}

const supersetLewo = (function () {
    // ========== 私有常量与缓存（闭包私有，外部不可访问） ==========
    // 设备ID本地存储Key：localStorage + cookie共用
    const STORAGE_KEY = 'analytics.device_id.uuid_v4';
    // 内存缓存设备UUID，避免重复读取存储
    let memoryCache: string | null = null;
    // 全局缓存用户/设备公共信息，上报顶层user字段统一复用
    let globalUserInfo: ISupersetUserInfo = {};

    let initInfoFlag = false;

    /**
     * 生成标准 UUID v4 设备唯一标识
     * 优先级：原生crypto.randomUUID > crypto.getRandomValues > Math.random伪随机兜底
     * @returns {string} 小写标准UUID v4字符串
     */
    function createUuidV4(): string {
        const cryptoObj = (globalThis as any).crypto;
        // 浏览器原生高性能UUID接口
        if (cryptoObj?.randomUUID) {
            return cryptoObj.randomUUID().toLowerCase();
        }
        // 支持加密随机字节，手动构造v4规范UUID
        if (cryptoObj?.getRandomValues) {
            const bytes = new Uint8Array(16);
            cryptoObj.getRandomValues(bytes);
            // UUID v4 固定版本位 0x40、变种位 0x80
            bytes[6] = (bytes[6] & 0x0f) | 0x40;
            bytes[8] = (bytes[8] & 0x3f) | 0x80;
            // 字节转两位十六进制字符串
            const hex = Array.from(bytes, function (val) {
                return val.toString(16).padStart(2, '0');
            }).join('');
            // 拼接标准UUID分隔格式
            return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' +
                hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
        }
        // 最低兼容兜底：Math.random生成伪随机UUID（熵较低，仅无加密API场景使用）
        return generatePseudoUuid();
    }

    /**
     * Math.random 伪随机UUID生成器，兼容极老浏览器
     * @returns {string} 伪随机UUID v4格式字符串
     */
    function generatePseudoUuid(): string {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            const r = (Math.random() * 16) | 0;
            const v = c === 'x' ? r : (r & 0x3) | 0x8;
            return v.toString(16);
        });
    }

    /**
     * 安全读取Cookie，自动转义正则特殊字符，防止匹配失效
     * @param {string} name cookie键名
     * @returns {string | null} cookie值，无则返回null
     */
    function getCookie(name: string): string | null {
        try {
            // 转义 . * + ? $ 等正则特殊符号
            const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
            const reg = new RegExp('(^| )' + escapedName + '=([^;]+)');
            const match = document.cookie.match(reg);
            return match ? match[2] : null;
        } catch (e) {
            // cookie读取异常直接返回空
            return null;
        }
    }

    /**
     * 设置持久化Cookie，有效期1年，自动适配HTTPS Secure标识
     * @param {string} name cookie键名
     * @param {string} value cookie存储值
     */
    function setCookie(name: string, value: string): void {
        try {
            const isHttps = window.location.protocol === 'https:';
            const parts = [
                name + '=' + value,
                'max-age=31536000', // 有效期365天
                'path=/', // 全站生效
                'SameSite=Lax' // 防跨站劫持
            ];
            // HTTPS环境追加Secure标识
            if (isHttps) parts.push('Secure');
            document.cookie = parts.join(';');
        } catch (e) { }
    }

    /**
     * 时间格式化工具，统一输出 yyyy-MM-dd HH:mm:ss
     * @returns {string} 格式化后的标准时间字符串
     */
    function formatTime(): string {
        const date_t = new Date();
        const y_t = date_t.getFullYear();
        const m_t = String(date_t.getMonth() + 1).padStart(2, '0');
        const d_t = String(date_t.getDate()).padStart(2, '0');
        const h_t = String(date_t.getHours()).padStart(2, '0');
        const min_t = String(date_t.getMinutes()).padStart(2, '0');
        const sec_t = String(date_t.getSeconds()).padStart(2, '0');
        return y_t + "-" + m_t + "-" + d_t + " " + h_t + ":" + min_t + ":" + sec_t;
    }

    /**
     * 填充单条埋点事件默认字段，缺失字段自动补空/默认行为类型，自动填充事件时间
     * @param {ISupersetReportItem} eventItem 业务传入的单条埋点原始参数
     * @returns {ISupersetReportItem} 补全默认值后的标准事件对象
     */
    function fillEventDefault(eventItem: ISupersetReportItem): ISupersetReportItem {
        // 事件字段默认模板，对齐后端data数组字段规范
        const defaultEvent: ISupersetReportItem = {
            element_position: "",    // 产品定义元素位置编码（唯一标识）
            position_name: "",       // 元素位置中文名称
            page_code: "",           // OMS后台页面编码，无则空字符串
            page_name: "",           // OMS后台页面名称，无则空字符串
            floor_id: "",            // OMS后台楼层ID
            floor_name: "",          // OMS后台楼层名称
            element_type: "",        // 元素枚举：page/vlist/plist/res/act/link等
            element_name: "",        // 元素内部名称/标题
            content_id: "",          // 最小颗粒度内容ID（游戏/视频ID）
            content_title: "",       // 内容标题名称
            ext_attr1: "",           // 扩展属性1，存放自定义附属信息
            ext_attr2: "",           // 扩展属性2，存放附属ID类参数
            action_type: "曝光",     // 行为枚举：曝光/点击/开始播放/结束播放/分享/订购/启动/退出/切后台
            action_value: "",        // 行为附属值：播放时长填秒数、订购填金额(单位分)、无附属数据填空
            event_time: ""           // 事件发生时间，不传则自动生成当前标准时间
        };
        // 业务参数覆盖默认模板
        const merged = Object.assign({}, defaultEvent, eventItem);
        // 未传入时间自动填充当前客户端时间
        if (!merged.event_time) merged.event_time = formatTime();
        return merged;
    }

    // ========== 对外暴露公共API ==========
    return {
        // 全局埋点配置项
        config: {
            reportUrl: 'https://sup.daoran.tv/bi-api/api/game/lewo/batch', // 批量上报接口地址
            // reportUrl: '/bi-api/api/game/lewo/batch', // 批量上报接口地址
            defaultHeaders: [] as Array<{ name: string; value: string }>, // 默认全局请求头数组
            defaultContentType: 'application/json;charset=UTF-8' // 请求体类型
        },

        /**
         * 设置全局用户/设备公共信息（上报顶层user对象，全局复用）
         * @param {ISupersetUserInfo} userObj 用户设备公共参数集合
         */
        initUserInfo: function (userObj: ISupersetUserInfo): void {
            if (initInfoFlag) { return; }
            initInfoFlag = true;
            // 未传入设备ID时，自动生成持久化UUID填充
            if (!userObj.device_id) {
                userObj.device_id = this.createDeviceId();
            }
            // 合并覆盖全局缓存，保留旧字段，新参数覆盖
            globalUserInfo = Object.assign({}, globalUserInfo, userObj);

            try {
                // 1. 异步加载 H5 专属 SDK
                (function (w: any, d: Document, s: string, q: string, i: string) {
                    w[q] = w[q] || [];
                    const f = d.getElementsByTagName(s)[0],
                        j = d.createElement(s) as HTMLScriptElement;
                    j.async = true;
                    j.id = 'beacon-aplus';
                    // ✅ 使用 H5 网页专属 SDK 地址
                    j.src = 'https://d.alicdn.com/alilog/mlog/aplus/' + i + '.js';
                    f.parentNode.insertBefore(j, f);
                })(window, document, 'script', 'aplus_queue', '203467608');

                // ========= 基础配置 =========
                // 2. 设置 AppKey (请确保与友盟后台 H5/Web 应用的 AppKey 一致)
                aplus_queue.push({
                    action: 'aplus.setMetaInfo',
                    arguments: ['appKey', '6a55f95f6f259537c7c966c8'] // 替换你的Umini AppKey
                });
                // 3. 声明终端类型为 PC (关键配置)
                aplus_queue.push({
                    action: 'aplus.setMetaInfo',
                    arguments: ['aplus-terminal', 'pc']
                });
                // 4. 采集模式配置
                // 传统多页网站(PC)建议改为 'AUTO'；如果是 Vue/React 单页应用(SPA)保持 'MAN'
                aplus_queue.push({
                    action: 'aplus.setMetaInfo',
                    arguments: ['aplus-waiting', 'AUTO']
                });
                // 调试模式，上线务必改为false
                aplus_queue.push({
                    action: 'aplus.setMetaInfo',
                    arguments: ['DEBUG', false]
                });

                // ✅【必须补充】显式初始化SDK
                aplus_queue.push({
                    action: 'aplus.init'
                });
            } catch (e) { }

            try {
                // 设置用户唯一ID（登录/游客都可以设置）
                const u_user_id = userObj.uid || userObj.device_id || '';
                aplus_queue.push({
                    action: 'aplus.setMetaInfo',
                    arguments: ['userId', u_user_id]
                });
            } catch (e) { }
        },

        /**
         * 获取当前全局缓存的user公共信息（拷贝返回，防止外部篡改缓存）
         * @returns {ISupersetUserInfo} 完整user公参对象
         */
        getUserInfo: function (): ISupersetUserInfo {
            return Object.assign({}, globalUserInfo);
        },

        /**
         * 获取或生成持久化设备唯一ID
         * 读取优先级：内存缓存 > localStorage > cookie > 新建UUID
         * @returns {string} 小写标准UUID v4 device_id
         */
        createDeviceId: function (): string {
            // 内存存在直接返回，减少存储读取
            if (memoryCache) return memoryCache;
            // 第一步读取localStorage
            try {
                const storageId = localStorage.getItem(STORAGE_KEY);
                if (storageId?.trim()) {
                    memoryCache = storageId.toLowerCase();
                    return memoryCache;
                }
            } catch (e) { }
            // 第二步读取cookie
            const cookieId = getCookie(STORAGE_KEY);
            if (cookieId?.trim()) {
                memoryCache = cookieId.toLowerCase();
                // 同步写入localStorage，双存储统一
                try { localStorage.setItem(STORAGE_KEY, memoryCache); } catch (e) { }
                return memoryCache;
            }
            // 无存储记录，新建UUID并持久化
            const newId = createUuidV4();
            memoryCache = newId;
            try { localStorage.setItem(STORAGE_KEY, newId); } catch (e) { }
            setCookie(STORAGE_KEY, newId);
            return newId;
        },

        /**
         * 重置清除本地全部设备ID缓存（退出账号/清除游客标识场景使用）
         */
        resetDeviceId: function (): void {
            memoryCache = null;
            // 删除本地存储
            try { localStorage.removeItem(STORAGE_KEY); } catch (e) { }
            // 过期销毁cookie
            try {
                const isHttps = window.location.protocol === 'https:';
                const cookieParts = [STORAGE_KEY + '=', 'max-age=0', 'path=/', 'SameSite=Lax'];
                if (isHttps) cookieParts.push('Secure');
                document.cookie = cookieParts.join(';');
            } catch (e) { }
        },

        /**
         * 上报请求中转封装，调用底层ES5 ajax
         * @param {ISupersetReportItem} dataObj 完整上报报文 {user:{}, data:[]}
         */
        supersetAjax: function (dataObj: ISupersetReportItem): void {
            this.ajax({
                url: this.config.reportUrl,
                data: dataObj,
                type: 'post',
                dataType: 'json',
                headers: [],
                success: function (xhr: XMLHttpRequest /*, rsp */) {
                    // 上报成功回调，业务可自行扩展
                },
                error: function (xhr: XMLHttpRequest | null, rsp: any) {
                    console.error('[supersetLewo 埋点上报失败]', rsp);
                }
            });
        },

        /**
         * ES5 底层原生XMLHttpRequest AJAX封装（还原最初版本逻辑，无Promise/Beacon）
         * @param {ISupersetAjaxConfig} config 请求配置对象
         */
        ajax: function (config: ISupersetAjaxConfig): void {
            let url = config.url;
            let data = config.data;
            const dataAsync = config.async !== false;
            const type = (config.type || 'GET').toUpperCase();
            const contentType = config.contentType || this.config.defaultContentType;
            const dataType = config.dataType;
            const headers = config.headers || this.config.defaultHeaders;
            const fnSuccess = config.success || function () { };
            const fnError = config.error || function () { };
            let xmlhttp: any;

            // 兼容IE低版本XMLHttpRequest
            if (typeof window != 'undefined' && window.XMLHttpRequest) {
                xmlhttp = new XMLHttpRequest();
            } else if (typeof (ActiveXObject as any) != 'undefined') {
                xmlhttp = new (ActiveXObject as any)("Microsoft.XMLHTTP");
            } else {
                fnError(null, { error: 'XMLHttpRequest is not supported in this environment' });
                return;
            }

            xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState == 4) {
                    let rsp = xmlhttp.responseText || xmlhttp.responseXML;
                    let parseError = false;
                    // JSON解析异常捕获，防止页面报错
                    if (dataType == 'json' && typeof rsp == 'string') {
                        try {
                            rsp = JSON.parse(rsp);
                        } catch (e) {
                            parseError = true;
                        }
                    }
                    if (parseError) {
                        fnError(xmlhttp, rsp);
                    } else if (xmlhttp.status == 200) {
                        fnSuccess(xmlhttp, rsp);
                    } else {
                        fnError(xmlhttp, rsp);
                    }
                }
            };

            xmlhttp.open(type, url, dataAsync);
            // 追加自定义请求头
            for (let i = 0; i < headers.length; ++i) {
                xmlhttp.setRequestHeader(headers[i].name, headers[i].value);
            }
            xmlhttp.setRequestHeader('Content-Type', contentType);
            // console.log('[supersetLewo 上报数据]', data);
            // 对象转JSON字符串发送
            data = JSON.stringify(data);
            xmlhttp.send(data);
        },

        /**
         * 单条埋点事件上报
         * @param {ISupersetReportItem} eventParam 单条事件埋点参数，字段对齐data数组规范
         */
        superBatchReport: function (eventParam: ISupersetReportItem): void {
            // 填充缺失默认字段与事件时间
            const eventItem = fillEventDefault(eventParam);
            // 组装标准上报报文
            const reportBody = {
                user: this.getUserInfo(), // 全局公共用户设备信息
                data: [eventItem] // 单事件数组
            };
            this.supersetAjax(reportBody);

            try {
                const action_type = eventParam.action_type == '点击' ? 'CLICK' : 'EXPOSURE';
                const eventName = eventParam.element_position + '_' + action_type;

                aplus_queue.push({
                    action: 'aplus.record',
                    // 第二个参数事件类型：CLICK / EXPOSURE / PAGE等，常规点击用CLICK
                    arguments: [eventName, action_type, eventParam]
                });
            } catch (e) {
                console.log("superBatchReport-umeng error", e);
            }
        },

        /**
         * 批量多条埋点事件上报（一次性上报多个行为，减少请求次数）
         * @param {ISupersetReportItem[]} eventList 多条埋点事件对象数组
         */
        batchReporting: function (eventList: ISupersetReportItem[]): void {
            // 非数组/空数组直接终止上报
            if (!Array.isArray(eventList) || eventList.length === 0) return;
            // 批量填充每条事件默认参数
            const filledData: ISupersetReportItem[] = [];
            for (let i = 0; i < eventList.length; i++) {
                filledData.push(fillEventDefault(eventList[i]));

                try {
                    const action_type = eventList[i].action_type == '点击' ? 'CLICK' : 'EXPOSURE';
                    const eventName = eventList[i].element_position + '_' + action_type;

                    aplus_queue.push({
                        action: 'aplus.record',
                        // 第二个参数事件类型：CLICK / EXPOSURE / PAGE等，常规点击用CLICK
                        arguments: [eventName, action_type, eventList[i]]
                    });
                } catch (e) {
                    console.log("batchReporting-umeng error", e);
                }
            }
            // 组装批量上报报文
            const reportBody = {
                user: this.getUserInfo(),
                data: filledData
            };
            this.supersetAjax(reportBody);
        },
    };
})();

// CommonJS 模块导出（兼容 IIFE 逻辑）
export default supersetLewo;