import { _decorator, SpriteFrame, Node, Sprite, instantiate, Label, Prefab, Color, Size, UITransform, RichText, Component, Texture2D, ImageAsset } from 'cc';
import { httpRequest } from '../network/HttpRequest';
import { app } from '../../app/app';
const { ccclass } = _decorator;

//@ts-ignore
import CryptoJS from "crypto-js";

type ConstructorOf<T> = new (...args: any[]) => T;

// 定义数据接口
interface DataObject {
    [key: string]: string | number | boolean;
}

/** 事件名称 */
export enum EventType {
    /** 刷新玩家数据 */
    RefreshUserInfo = "RefreshUserInfo",
    /** 刷新玩家数据成功 */
    RefreshUserInfoSuccess = "RefreshUserInfoSuccess",
}


// 定义阈值和对应的num值
const sizeThresholds = [
    { size: 20000000, num: 100 },
    { size: 19000000, num: 95 },
    { size: 18000000, num: 90 },
    { size: 17000000, num: 85 },
    { size: 16000000, num: 80 },
    { size: 15000000, num: 75 },
    { size: 14000000, num: 70 },
    { size: 13000000, num: 65 },
    { size: 12000000, num: 60 },
    { size: 11000000, num: 55 },
    { size: 10000000, num: 50 },
    { size: 9000000, num: 45 },
    { size: 8000000, num: 40 },
    { size: 7000000, num: 35 },
    { size: 6000000, num: 30 },
    { size: 5000000, num: 25 },
    { size: 4000000, num: 20 },
    { size: 3000000, num: 15 },
    { size: 2000000, num: 10 },
    { size: 1000000, num: 5 },
    { size: 500000, num: 2.5 },
    { size: 250000, num: 1.5 }
];

/** 用户代理等级和图片对照表 */
const AGENT_LV_TO_PIC = {
    ["等级青铜"] : "a",
    ["等级白银"] : "b",
    ["等级黄金"] : "c",
    ["等级VIP"] : "d",
    ["等级超级VIP"] : "e"
}

/** 通用工具类 */
@ccclass('Tools') 
export class Tools
{
    //#region Sprite相关操作
    /** 设置节点的SpriteFrame， 默认从resource/ui下面找 */
    static SetSpriteFrame(node:Node, uiname:string, uipath:string, fuc:Function = null) {
        app.manager.loader.load({
            bundle: "", // 不传入bundle，默认为resources
            path: 'xxx/xxxx',
            type: SpriteFrame,
            onComplete(asset){
                if (node){
                    let c = node.getComponent(Sprite)
                    if (c) c.spriteFrame = asset
                    if (fuc) fuc()
                }
            }
        })
    }

    /** 加载远程图片 */
    static remoteLoadSprite(url: string, node: Sprite, fuc?: Function) { 
        app.manager.loader.loadRemote( {
            url: url,
            ext: null,
            onComplete: (result: ImageAsset | null) => {
                if (result) {
                    if(node) {
                        let sp = new SpriteFrame()
                        let tex = new Texture2D();
                        tex.image = result;
                        sp.texture = tex
                        node.spriteFrame = sp
                        if (fuc) fuc()
                    }
                }
            }
        })
    }

    /** 设置子节点uisprite */
    static SetChildSprite(node:Node, path:string, uiname:string, uipath:string, fuc:Function = null) {
        let n = node.getChildByPath(path)
        if (n) this.SetSpriteFrame(n, uiname, uipath, fuc)
    }

    /** 
     * 设置艺术字
     * itemPath:字体预制件位置, numPath:字体图片位置, pre:图片名前缀
    */
    // static SetArtNums(str:any, item:Node, itemPath:string = "ui/numbers/num_Item", numPath:string = "ui/numbers", pre:string = "numbers_0") {
    //     str = String(str)
    //     item.destroyAllChildren()
    //     let m_resLoader = new ResLoader();
    //     m_resLoader.loadPrefabNode(itemPath, (prefab:Node) => { 
    //         console.log(itemPath, prefab)
    //         // 根据字符串长度，显示对应数量的数字图片
    //         for (let i = 0; i < str.length; i++) {
    //             let n = Tools.AddChild(item, prefab, "num_" + i)
    //             n.active = true
    //             this.SetSpriteFrame(n, pre + (str[i] == "." ? "dot" : str[i]), numPath)
    //         }
    //     })
    // }
    //#endregion
    

    //#region http相关
    /** 发送http请求 */
    static httpReq(str:string, param:any, callback:Function, failCallBack:Function = null) {
        httpRequest.post("/agent/api/" + str, param, callback, failCallBack)
    }
    //#endregion


    //#region Node 相关
    /** 添加子节点 */
    static AddChild(node:Node, prefab:Node|Prefab, name:string = null):Node {
       var n = instantiate(prefab as Node)
       node.addChild(n)
       if (name) n.name = name
       return n
    }

    /** 设置子节点显示 */
    static ActChild(node:Node, path:string, act:boolean)
    {
        let n = node.getChildByPath(path)
        if (n) n.active = act
    }

    /** 获取子节点组件 */
    static GetChildComp<T extends Component>(node: Node, path: string, compClass: ConstructorOf<T>): T {
        return node.getChildByPath(path)?.getComponent(compClass);
    }
    
    //#endregion


    //#region Text 相关
    /** 设置子节点文字 */
    static SetText(node:Node, str:string) {
        str = String(str)
        node.getComponent(Label).string = str
    }
    /** 设置子节点文字 */
    static SetChildText(node:Node, path:string, str:string) {
        str = String(str)
        let n = node.getChildByPath(path)
        n.getComponent(Label).string = str
    }
    /** 设置子节点文字 */
    static SetChildRichText(node:Node, path:string, str:string) {
        str = String(str)
        let n = node.getChildByPath(path)
        n.getComponent(RichText).string = str
    }
    /** 设置节点文字颜色 */
    static SetLabColor(node:Node, str:string) {
        node.getComponent(Label).color = Color.fromHEX(new Color(), str)
    }
    /** 设置子节点字体颜色 */
    static SetChildLabColor(node:Node, path:string, str:string) {
        let n = node.getChildByPath(path)
        n.getComponent(Label).color = Color.fromHEX(new Color(), str)
    }

    /** 设置节点大小 */
    static SetSize(node:Node, size:Size) {
        node.getComponent(UITransform).setContentSize(size);
    }

    /** 设置节点触摸事件 */
    static SetTouchEndEvt(node:Node, func:Function) {
        node.off(Node.EventType.TOUCH_END)
        node.on(Node.EventType.TOUCH_END, func)
    }

    /** 设置子节点触摸事件 */
    static SetChildTouchEndEvt(node:Node, path:string, func:Function) {
        let n = node.getChildByPath(path)
        if (n) this.SetTouchEndEvt(n, func)
    }
    //#endregion


    //#region 字符串操作
    /** 
     ** 替换占位符{0},{1}.... 
     ** 例子: const message = Tools.stringFormat("My name is {0} and I am {1} years old.", name, age);
    */
    static StringFormat(format: string, ...args: any[]): string {
        return format.replace(/{(\d+)}/g, (match, index) => {
          return typeof args[index] !== "undefined" ? args[index] : match;
        });
    }

    static StringLFormat(format: string, ...args: any[]): string {
        format = this.GetLocalized(format)
        return this.StringFormat(format, ...args)
    }
    //#endregion


    //#region 其他
    /** 本地化 */
    static GetLocalized(str : string) {
        return str
        //return LabelConfig[str] ? LabelConfig[str][LocalizadManager.getInstance().getLanauge()-1] : str
    }
    /** 压缩上传图片成base64 */
    static CompressImageToBase64(param:any, callback:Function = null){
        var fileList = param.files[0];
        var reader = new FileReader();
        reader.readAsDataURL(fileList);
        reader.onload = (event) => {
            let image = new Image() //新建一个img标签（还没嵌入DOM节点)
            var dataImg  = event.target.result;
            var num = 1;
            //@ts-ignore
            image.src = event.target.result
            image.onload = () => {
                //由于不能将太多Base64字符给服务端发过于，咱们压缩一下
                //如果想支持更大图片，请继续加判断，增加除数
                // 检查文件大小是否超过20M
                if (fileList.size > 20000000) {
                    console.log("文件大小不能大于20M！");
                    param.value = '';
                    return;
                }
                // 根据文件大小设置num值
                for (const threshold of sizeThresholds) {
                    if (fileList.size > threshold.size) {
                        num = threshold.num;
                        break;
                    }
                }
                let canvas = document.createElement('canvas');
                let context = canvas.getContext('2d');
                let imageWidth = image.width / num;  //压缩后图片的大小
                let imageHeight = image.height / num;
                const minSize = 640; // 设置最小尺寸
                if (imageWidth < minSize || imageHeight < minSize) {
                    const scaleFactor = Math.max(minSize / imageWidth, minSize / imageHeight);
                    imageWidth *= scaleFactor;
                    imageHeight *= scaleFactor;
                }
                canvas.width = imageWidth;
                canvas.height = imageHeight;
                context.drawImage(image, 0, 0, imageWidth, imageHeight);
                dataImg = canvas.toDataURL('image/png');
                //此时的dataImg就是你要上传给服务器的字符
                param.value = '';
                if (callback) callback(dataImg)
                return dataImg;
            }
        };
    }

    /** 生成二维码 */
    // static SetQRCode(text: string, item : Node){
    //     const qr = QRCode(0, 'M');
    //     qr.addData(text);
    //     qr.make();
    //     const dataUrl = qr.createDataURL(4, 4);
    //     const img = new Image();
    //     img.src = dataUrl;

    //     assetManager.loadRemote(dataUrl, {ext : '.png'}, (err, imgAsset: ImageAsset) => {
    //         if (err) {
    //             console.error(err.message || err);
    //             return;
    //         }
    //         const sp = new SpriteFrame()
    //         const tx = new Texture2D()
    //         tx.image = imgAsset
    //         sp.texture = tx
    //         item.getComponent(Sprite).spriteFrame = sp
    //     })
    // }

    /** 通过base64字符串设置图片 */
    static SetBase64Pic(src: string, node: Node): void {
        let image = new Image()
        image.src = src // base 64是string，看后端返回是二进制，是否带头data:image/png;base64, 不带要手动添加
        image.onload = () => {
            let texture = new Texture2D()
            texture.image = new ImageAsset(image)
            let _frame = new SpriteFrame()
            _frame.texture = texture
            // 获取节点的容器
            let c = node.getComponent(Sprite)
            if (c) c.spriteFrame = _frame
        }    
    }

    /** 复制到剪切板 */
    static CopyToClipboard(str:string) {
        var input = str + '';
        const el = document.createElement('textarea');
        el.value = input;
        el.setAttribute('readonly', '');
        el.style.contain = 'strict';
        el.style.position = 'absolute';
        el.style.left = '-9999px';
        el.style.fontSize = '12pt'; // Prevent zooming on iOS
        
        const selection = getSelection();
        var originalRange = null;
        if (selection.rangeCount > 0) {
            originalRange = selection.getRangeAt(0);
        }
        document.body.appendChild(el);
        el.select();
        el.selectionStart = 0;
        el.selectionEnd = input.length;
        
        var success = false;
        try {
            success = document.execCommand('copy');
        } catch (err) {}
        
        document.body.removeChild(el);
        
        if (originalRange) {
            selection.removeAllRanges();
            selection.addRange(originalRange);
        }
        app.manager.ui.showToast("复制成功")
        return success;
    }

    /** 获取代理等级本地化 */
    static GetAgentLvLocalized(agentLv:string, lv :number) {
        return this.StringFormat(this.GetLocalized(agentLv), lv)
    }

    /** 设置代理等级图标 */
    // static SetAgentLvIcon(item:Node, agentLv:string, lv :number) {
    //     if (!AGENT_LV_TO_PIC[agentLv]) return
    //     var icon = "icon" + AGENT_LV_TO_PIC[agentLv] + this.Return2LengthNumber(lv)
    //     this.SetSpriteFrame(item, icon, "Lobby/ui/allagent/icon")
    // }

    /** 设置子节点代理等级图标 */
    // static SetChildAgentLvIcon(item:Node, path :string, agentLv:string, lv :number) {
    //     let n = item.getChildByPath(path)
    //     this.SetAgentLvIcon(n, agentLv, lv)
    // }

    /** 返回两位数 */
    static Return2LengthNumber(n : number) {
        return n < 10 ? "0" + n : n.toString()
    }

    //#endregion


    //#region 数学算法
    static MathClampZeroToOne(value: number): number {
        return Math.max(0, Math.min(1, value));
    }

    static MathClamp(value: number, min: number, max: number): number {
        return Math.max(min, Math.min(max, value));
    }
    //#endregion


    static OpenWeb(url:string) {
        const link = document.createElement('a');
        link.href = url;
        link.target = '_blank';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }


    /**
     * 获取指定长度随机字符串
     */
    public static getRandomStr (len:number) {
        let chars =
          'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz' 
        let maxPos = chars.length
        let pwd = ''
        for (let i = 0; i < len; i++) {
          pwd += chars.charAt(Math.floor(Math.random() * maxPos))
        }
        return pwd
    }

    /**
     * 使用 crypto-js 生成签名
     * @param data - 要签名的数据
     * @param key - 签名密钥
     * @param encrypt - 加密算法 (sha1, sha256)
     * @returns Promise<string> 签名结果
     */
    public static generateSignNative(
        data: Record<string, string>,
        key: string,
        encrypt: string = 'sha256'
    ): Promise<string> {
        // 1. 对数据进行排序
        const sortedData = Tools.sortData(data);

        // 2. 构建查询字符串（自定义实现）
        const queryString = Object.keys(sortedData)
            .map(k => encodeURIComponent(k) + "=" + encodeURIComponent(sortedData[k]))
            .join("&");

        // 3. URL解码并拼接密钥
        const decodedString = decodeURIComponent(queryString);
        const str = decodedString + key;

        // 4. 根据算法生成签名
        let hash;
        switch (encrypt.toLowerCase()) {
            case 'sha1':
                hash = CryptoJS.SHA1(str);
                break;
            case 'sha256':
            default:
                hash = CryptoJS.SHA256(str);
                break;
        }

        // 5. 返回十六进制字符串
        return Promise.resolve(hash.toString(CryptoJS.enc.Hex));
    }

    // 示例排序函数（你已有的话可以直接用）
    public static sortData(data: Record<string, string>): Record<string, string> {
        return Object.keys(data)
            .sort()
            .reduce((acc, key) => {
                acc[key] = data[key];
                return acc;
            }, {} as Record<string, string>);
    }



    //#region 加密解密
    /** 解析JWT令牌 */
    public static parseJWT(token: string) {
        try {
            const parts = token.split('.');
            if (parts.length !== 3) {
                throw new Error('Invalid JWT token');
            }
            
            // 解码 payload 部分（第二部分）
            const payload = JSON.parse(atob(parts[1]));
            return payload;
        } catch (error) {
            console.error('Failed to parse JWT token:', error);
            return null;
        }
    }


    /**
     * 解密 DES-ECB 模式加密的数据
     * @param encryptedData base64编码的加密数据
     * @param secretKey 8位密钥
     * @returns 解密后的字符串
     */
    static desEcbDecrypt(encryptedData: string, secretKey: string): string {
        try {
            // 确保密钥为8位 (PHP的openssl_encrypt会自动截取前8位)
            const key = secretKey.length > 8 ? secretKey.substring(0, 8) : this.padKey(secretKey, 8);
            
            // 创建CryptoJS格式的密钥
            const keyWordArray = CryptoJS.enc.Utf8.parse(key);
            
            // 解密
            const decrypted = CryptoJS.DES.decrypt(
                encryptedData,
                keyWordArray,
                {
                    mode: CryptoJS.mode.ECB,
                    padding: CryptoJS.pad.Pkcs7
                }
            );
            
            return decrypted.toString(CryptoJS.enc.Utf8);
        } catch (error) {
            console.error('DES-ECB decryption failed:', error);
            return '';
        }
    }

    /**
     * 加密 DES-ECB 模式数据
     * @param data 待加密的数据
     * @param secretKey 8位密钥
     * @returns base64编码的加密数据
     */
    static desEcbEncrypt(data: string, secretKey: string): string {
        try {
            // 确保密钥为8位
            const key = secretKey.length > 8 ? secretKey.substring(0, 8) : this.padKey(secretKey, 8);
            
            // 创建CryptoJS格式的密钥
            const keyWordArray = CryptoJS.enc.Utf8.parse(key);
            
            // 加密
            const encrypted = CryptoJS.DES.encrypt(
                data,
                keyWordArray,
                {
                    mode: CryptoJS.mode.ECB,
                    padding: CryptoJS.pad.Pkcs7
                }
            );
            
            return encrypted.toString();
        } catch (error) {
            console.error('DES-ECB encryption failed:', error);
            return '';
        }
    }

    /**
     * 补齐或截断密钥到指定长度
     * @param key 原始密钥
     * @param length 目标长度
     */
    private static padKey(key: string, length: number): string {
        if (key.length > length) {
            return key.substring(0, length);
        } else if (key.length < length) {
            while (key.length < length) {
                key += '\0'; // 用null字符补齐
            }
            return key;
        }
        return key;
    }

    /**
     * 3DES-ECB 解密 (Triple DES)
     * @param encryptedData base64编码的加密数据
     * @param secretKey 24位密钥 (3DES需要24字节密钥)
     * @returns 解密后的字符串
     */
    static tripleDesEcbDecrypt(encryptedData: string, secretKey: string): string {
        try {
            // 确保密钥为24位
            const key = this.padKey(secretKey, 24);
            
            // 创建CryptoJS格式的密钥
            const keyWordArray = CryptoJS.enc.Utf8.parse(key);
            
            // 解密
            const decrypted = CryptoJS.TripleDES.decrypt(
                encryptedData,
                keyWordArray,
                {
                    mode: CryptoJS.mode.ECB,
                    padding: CryptoJS.pad.Pkcs7
                }
            );
            
            return decrypted.toString(CryptoJS.enc.Utf8);
        } catch (error) {
            console.error('3DES-ECB decryption failed:', error);
            return '';
        }
    }

    /**
     * 3DES-ECB 加密 (Triple DES)
     * @param data 待加密的数据
     * @param secretKey 24位密钥
     * @returns base64编码的加密数据
     */
    static tripleDesEcbEncrypt(data: string, secretKey: string): string {
        try {
            // 确保密钥为24位
            const key = this.padKey(secretKey, 24);
            
            // 创建CryptoJS格式的密钥
            const keyWordArray = CryptoJS.enc.Utf8.parse(key);
            
            // 加密
            const encrypted = CryptoJS.TripleDES.encrypt(
                data,
                keyWordArray,
                {
                    mode: CryptoJS.mode.ECB,
                    padding: CryptoJS.pad.Pkcs7
                }
            );
            
            return encrypted.toString();
        } catch (error) {
            console.error('3DES-ECB encryption failed:', error);
            return '';
        }
    }

    //#endregion
}
