import { _decorator, Director, director, Label, Node, Overflow, RichText, tween, UITransform, Vec3 } from 'cc';
import { StaticTxt } from './StaticTxt';
const { ccclass, property } = _decorator;

export class Tools {
    private static _instance: Tools;

    ctx: any = null

    public static get instance(): Tools {
        if (!this._instance) {
            this._instance = new Tools();

            let canvas = document.createElement('canvas');
            this._instance.ctx = canvas.getContext('2d')!;
        }

        return this._instance;
    }

}

/**RichText元素*/
interface Segment {
    type: "label" | "image";
    value: string;
}

interface WrapRes {
    result: string;
    lastLineWidth: number;
}

interface LangTxt {
    labels: Label[];      // Label 组件数组
    richTexts: RichText[]; // RichText 组件数组
}

export function fixNum(num: number): string {
    return (num / 10000).toFixed(2)
}

// 需要代码计算空格处理换行的婆罗米系文字
export function isBrahmic(lang: string) {
    let arr = ["th", "my"]
    return arr.indexOf(lang) != -1
}

export function getLabelsAndRichTexts(node: Node, langText: LangTxt): LangTxt {


    const label = node.getComponent(Label);
    const richText = node.getComponent(RichText);

    const staticTxt = node.getComponent(StaticTxt)
    if (label && staticTxt) {
        langText.labels.push(label);
    }
    if (richText && staticTxt) {
        langText.richTexts.push(richText);
    }
    // 遍历所有子节点
    node.children.forEach(child => {
        getLabelsAndRichTexts(child, langText);
    });

    return langText
}

/**拿到节点下所有需要翻译的, 挂载了StaticTxt脚本的 Label*/
export function getAllLabels(node: Node, result: Label[] = []): Label[] {
    const label = node.getComponent(Label);
    const staticTxt = node.getComponent(StaticTxt)
    if (label && staticTxt) {
        result.push(label);
    }

    // 遍历所有子节点
    node.children.forEach(child => {
        getAllLabels(child, result);
    });

    return result;
}

/**拿到节点下所有需要翻译的, 挂载了StaticTxt脚本的 Label*/
export function getAllRichTexts(node: Node, result: RichText[] = []): RichText[] {
    const richText = node.getComponent(RichText);
    const staticTxt = node.getComponent(StaticTxt)
    if (richText && staticTxt) {
        result.push(richText);
    }

    // 遍历所有子节点
    node.children.forEach(child => {
        getAllRichTexts(child, result);
    });

    return result;
}



export function getTranslate(dict, key) {
    let str = dict[key] ?? key
    return str;
}

export function getTimezoneOffsetString(): string {

    const pad = (n: number) => (n < 10 ? '0' + n : String(n));

    const offset = -new Date().getTimezoneOffset(); // 单位是分钟，注意要取反
    const sign = offset >= 0 ? "+" : "-";
    const hours = pad(Math.floor(Math.abs(offset) / 60))
    const minutes = pad(Math.abs(offset) % 60);

    return `(GMT${sign}${hours}:${minutes})`;
}

export function updateLang(node: Node, dict, lang:string) {

    let langText: LangTxt = { labels: [], richTexts: [] }
    getLabelsAndRichTexts(node, langText)

    langText.labels.forEach((label, i) => {
        // console.log(`label.node.name: ${label.node.name}`)

        const staticTxt = label.node.getComponent(StaticTxt)
        const bResize = label.overflow == Overflow.RESIZE_HEIGHT

        let key = staticTxt?.key
        if (dict[key]) {

            if (isBrahmic(lang) && bResize) {
                label.string = wrapTextBySpace(label, dict[key])
            } else {
                label.string = dict[key]
            }

            if (label.node.activeInHierarchy) {
                label.updateRenderData()
            }
        }
    })

    langText.richTexts.forEach((richText, i) => {

        const staticTxt = richText.node.getComponent(StaticTxt)
        richText.maxWidth = staticTxt.maxWidth
        richText.string = wrapRichTextBySpace(richText, staticTxt.key, dict,lang)
    })

    return langText
}

export function wrapRichTextBySpace(richText: RichText, key: string, dict, lang): string {

    // key like this: Label_Rules_6_14_2 <img src='dates' /> Label_Rules_6_14_3
    const segmentArr: Segment[] = [];
    const regex = /Label_[^<\s]+|<img[^>]+>/g;
    let match: RegExpExecArray | null;
    while ((match = regex.exec(key)) !== null) {
        if (match[0].startsWith("Label_")) {

            let key = match[0].split("Label_")[1]
            if (dict[key]) {
                segmentArr.push({ type: "label", value: dict[key] });
            }

        } else {
            segmentArr.push({ type: "image", value: match[0] }); // "<img src='dates' />"
        }
    }

    // console.log("segmentArr:", segmentArr);

    /*
    segmentArr:
    [
        {
            "type": "label",
            "value": "Tap"
        },
        {
            "type": "image",
            "value": "<img src='dates' />"
        },
        {
            "type": "label",
            "value": "to select the dates of games to be shown in History."
        }
    ]
    */

    let wrapResult: WrapRes = { result: "", lastLineWidth: 0 }
    segmentArr.forEach((part, i) => {

        if (isBrahmic(lang)) {
            if (part.type == "label") {
                wrapResult = wrapTextByRichTextWidth(richText, part.value, wrapResult)
            } else if (part.type == "image") {

                let img = part.value.match(/src=['"]([^'"]+)['"]/)
                const spriteFrame = richText.imageAtlas.getSpriteFrame(img[1]);

                if (spriteFrame) {
                    const rect = spriteFrame.rect; // 原始图片矩形
                    // console.log("原始图片宽度:", rect.width);

                    // 图片宽度 + 最后一行宽度 比 最大宽度大，图片换行放到下一行去
                    if (wrapResult.lastLineWidth + rect.width > richText.maxWidth) {
                        wrapResult.result += "\n" + part.value
                        wrapResult.lastLineWidth = rect.width
                    } else {
                        // 放得下就放在最后一行
                        wrapResult.result += part.value
                        wrapResult.lastLineWidth += rect.width
                    }
                }
            }
        }else{
            // 非婆罗米系文字，引擎自动换行就能处理好
            // 不需要手动计算
            wrapResult.result += part.value
        }

    })

    return wrapResult.result
}


// 富文本换行
export function wrapTextByRichTextWidth(richText: RichText, str: string, lastWrapResult: WrapRes = { result: "", lastLineWidth: 0 }): WrapRes {
    const fontSize = richText.fontSize;
    const fontFamily = richText.fontFamily ?? 'Arial'
    const maxWidth = richText.maxWidth // richText 最大宽度

    let wrapResult = lastWrapResult;

    Tools.instance.ctx.font = `${fontSize}px ${fontFamily}`;

    const words = str.split(' ')
    let line = '';
    let result = '';

    let endIdx = words.length - 1
    for (let i = 0; i < words.length; i++) {
        let word = words[i]

        console.log("word:", word)

        let testLine = line + " " + word

        const width = wrapResult.lastLineWidth + Tools.instance.ctx.measureText(testLine).width;

        console.log("width = ", width, "maxWidth = ", maxWidth)


        // 长度超了放到下一行去
        if (width + 5 > maxWidth && line.length > 0) {
            if (i == endIdx) {

                console.log("最后一个单词长度超了")


                result += line + '\n' + word;
                wrapResult.lastLineWidth = Tools.instance.ctx.measureText(word).width;
            } else {

                console.log("单词长度超了，换行")


                result += line + '\n';
                line = word
                wrapResult.lastLineWidth = 0
            }
        } else {
            if (i == endIdx) {

                console.log("最后一个单词，拼在屁股后面")


                result += testLine;
                wrapResult.lastLineWidth = Tools.instance.ctx.measureText(testLine).width;

            } else {

                console.log("拼在屁股后面")

                line = testLine;
            }
        }
    }

    console.log("循环结束, ", result)

    wrapResult.result += result

    return wrapResult;
}



// 按单词换行
export function wrapTextBySpace(label: Label, str: string): string {


    const fontSize = label.fontSize;
    const fontFamily = label.fontFamily ?? 'Arial'
    const maxWidth = label.node.getComponent(UITransform).width; // Label 最大宽度

    const words = str.split(' ')

    let line = '';
    let result = '';
    // const canvas = document.createElement('canvas');
    // const ctx = canvas.getContext('2d')!;
    Tools.instance.ctx.font = `${fontSize}px ${fontFamily}`;

    let endIdx = words.length - 1
    for (let i = 0; i < words.length; i++) {
        let word = words[i]

        // console.log("word = ", word)

        let testLine = line + " " + word

        const width = Tools.instance.ctx.measureText(testLine).width;

        // 长度超了放到下一行去
        if (width > maxWidth && line.length > 0) {
            if (i == endIdx) {
                result += line + '\n' + word;
            } else {
                result += line + '\n';
                line = word
            }
        } else {
            if (i == endIdx) {
                result += testLine;
            } else {
                line = testLine;
            }
        }
    }

    // console.log("循环结束, ", result)

    return result;
}

export function waitNextFrame(): Promise<void> {
    return new Promise(resolve => {
        director.once(Director.EVENT_BEFORE_UPDATE, () => resolve());
    });
}

export function hideAllChildren(node: Node) {
    node.children.forEach(child => {
        child.active = false
    })
}

export function showAllChildren(node: Node) {
    node.children.forEach(child => {
        child.active = true
    })
}

export function showFromBottom(node: Node) {
    if (!node) {
        return
    }
    let height = node.getComponent(UITransform)?.height
    if (height) {
        height = 1920;
    }

    node.position = new Vec3(0, -height / 2)
    tween(node).to(0.15, { position: new Vec3() }).start()
}

export function hideToBottom(node: Node, callFuc = null) {
    if (!node) {
        return
    }
    let height = node.getComponent(UITransform)?.height
    if (height) {
        height = 1920;
    }

    let endPos = new Vec3(0, -height)
    tween(node).to(0.15, { position: endPos }).call(() => {
        if (callFuc) {
            callFuc()
        }
    }).start()
}