const fs = require('fs');

//babel库相关，解析，转换，构建，生产
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
// const {replaceWith} = require("cheerio/lib/api/manipulation");
const generator = require("@babel/generator").default;
const print = console.log;

// const YY = require('./test')
// console.log(YY)
//读取文件
let encode_file = "./src_out.js",
    decode_file = "./src_decode.js";
// let encode_file = "./jiyan.js",decode_file = "./decode_result.js";
if (process.argv.length > 2) {
    encode_file = process.argv[2];
}
if (process.argv.length > 3) {
    decode_file = process.argv[3];
}

let jscode = fs.readFileSync(encode_file, {encoding: "utf-8"});
//转换为ast树
let ast = parser.parse(jscode);


const {
    decodeString,
    decodedBytecode,
    opcodeHandlerMap,
    encodedStringArray,
    parameterArray
} = require('./utils');
const { log } = require('console');
var globalObject$1 = {},
    globalObject$2 = {};
var emptyObject = globalObject$2;
var globalEmptyObj = Object.create(null);

function customArr() {
    var GM = [];
    return GM;
}
function Registers() {
    this.reg = [];
    this.init = function (Gs) {
        this.reg[Gs] = {
            v: void 0
        };
    };
    this.get = function (GZ) {
        return this.reg[GZ].v;
    };
    this.set = function (Gj, Go) {
        if (Array.isArray(Go) && typeof Go[0] === 'number'){
            // print(ha, hX+'')

        }
        // (ha === 13 || ha === 10|| ha === 8) &&
        if ( Array.isArray(Go) &&  Go.length === 60){
            // print(ha,'\n',hX)
            idx+= 1;
            // print(arrs['arr60' + idx])
            Go = new Proxy(Go, {
                set(target, propKey, value, receiver){ //拦截对象属性的设置，比如proxy.foo = v或proxy['foo'] = v，返回一个布尔值。
                    const temp = Reflect.set(target,propKey,value,receiver);
                    print(`${'arr60' + idx} -> set ${propKey} value -> ${value}`);
                    // if (propKey == 'pathname')debugger;
                    if (propKey === '27')debugger;
                    return temp;
                }
            })
            // debugger;

        }
        // (Gj === 14 || Gj === 10|| Gj === 8) &&
        if ( Gj === 9 &&Array.isArray(Go) &&  Go.length > 1000){
            print(Gj,'\t\t',Go + "")
            // debugger;
        }
        if ((Gj === 30) && Go &&  Go.length === 6){
            debugger
        }
        if ( Array.isArray(Go) &&  Go.length === 9){
            print(times, Go+'')
            // debugger
        }
        this.reg[Gj].v = Go;
    };
    this.clone = function () {
        var GH = new Registers();
        GH.reg = [].slice !== [].slice ? this.reg.slice(0) : this.reg.slice(0);
        return GH;
    };
}

function VirtualMachine(programCounter, opcodeHandlerCounter, registers, window) {
    this.stack = customArr();
    this.yStack = customArr();
    this.vStack = customArr();
    this.opcodeHandlerCounter = opcodeHandlerCounter;
    this.programCounter = programCounter;
    this.registers = registers;
    this.window$1 = window == null ? window : Object(window);
    this.window$2 = window;
    this.reg = 0;
    this.next = function () {
        var result = opcodeHandlerMap[this.opcodeHandlerCounter][decodedBytecode[this.programCounter++]];
        this.opcodeHandlerCounter = result[0];
        return result[1];
    };
}
function _newVmContext(programCounter, opcodeHandlerCounter, prevRegisters, _paramA, _paramC, isParamDUndefined, _paramD) {
    var vmStart = function () {
        "use strict";

        var registers = prevRegisters.clone();
        var vmContext = new VirtualMachine(programCounter, opcodeHandlerCounter, registers, this);
        var ih,
            iR,
            ib = Math.min(arguments.length, _paramC.length);
        if (isParamDUndefined) {
            registers.init(_paramD);
            registers.set(_paramD, arguments);
        }
        for (ih = 0, iR = _paramA.length; ih < iR; ++ih) {
            registers.init(_paramA[ih]);
        }
        for (ih = 0; ih < ib; ++ih) {
            registers.set(_paramC[ih], arguments[ih]);
        }
        for (ih = ib; ih < _paramC.length; ++ih) {
            registers.set(_paramC[ih], void 0);
        }
        return _vmStart(vmContext);
    };
    return vmStart;
}

function tryExecInstruction(opcodeHandler, vmContext) {
    try {
        return opcodeHandler(vmContext);
    } catch (GR) {
        console.log(GR);
        catchExecError(GR, vmContext);
    }
}
function catchExecError(Gz, vmContext) {
    var Gm = vmContext.vStack.pop();
    for (var GJ = 0; GJ < Gm.c; ++GJ) {
        vmContext.yStack.pop();
    }
    vmContext.yStack.push({
        N: true,
        z: Gz
    });
    vmContext.programCounter = Gm.Y;
    vmContext.opcodeHandlerCounter = Gm.K;
}

function _vmStart(vmContext) {
    // var key = `${vmContext.programCounter}:${vmContext.opcodeHandlerCounter}`;
    // if (!stackTrace[key]) {
    //     stackTrace[key] = [];
    // }
    // var currentTrace = [];
    // stackTrace[key].push(currentTrace);
    var opcode, iJ;
    for (;;) {
        if (emptyObject !== globalObject$2) {
            iJ = emptyObject;
            emptyObject = globalObject$2;
            return iJ;
        }
        opcode = vmContext.next();

        if (Array.isArray(vmContext.stack[0]) && vmContext.stack[0].length === 60 && Array.isArray(vmContext.stack[0][0])){
            let res = [];
            vmContext.stack[0].forEach((e,i)=>{
                if(e && e.length == 2){
                    res.push(i +'==' +e[1].length +'=>')
                    res.push(e[1]+'')
                }else {
                    res.push(i+'==0=>iii' )
                }

            })
            print([].slice.call(res).join('iii'))
        }
        print({opcodeHandlerCounter: vmContext.opcodeHandlerCounter, programCounter: vmContext.programCounter, reg: vmContext.reg})
        print('opCode', opcode, [].slice.call(vmContext.stack))
        if (vmContext.vStack.length === 0) {
            instructionHandlers(opcode, vmContext)
        } else {
            tryExecInstruction(instructionHandlers[opcode], vmContext)
        }
    }
}

function _initVm(programCounter, opcodeHandlerCounter, previousRegister, _paramA, _paramB, _paramC, _paramD, _paramE) {
    var registers = new Registers();
    var isParamDUndefined = _paramD !== void 0;
    for (var i = 0; i < _paramB.length; ++i) {
        registers.reg[_paramB[i]] = previousRegister.reg[_paramB[i]];
    }
    var vmContext = _newVmContext(programCounter, opcodeHandlerCounter, registers, _paramA, _paramC, isParamDUndefined, _paramD);
    if (_paramE !== void 0) {
        registers.init(_paramE);
        registers.set(_paramE, vmContext);
    }
    return vmContext;
}
_initVm(0, 0, null, [3, 2, 0, 1], [], [], void 0, void 0)();

function createOpcodeFunction(PQ, Pr, PO, PB) {
    "use strict";

    var iS = parameterArray[PQ];
    return _initVm(Pr, PO, PB, iS.C, iS.v, iS.t, iS.V, iS.l);
}
function instructionHandlers(opcode, vmContext) {
    switch (opcode){
        case 10:
            Object.defineProperty(vmContext.stack[vmContext.stack.length - 3], vmContext.stack[vmContext.stack.length - 2], {
                writable: true,
                configurable: true,
                enumerable: true,
                value: vmContext.stack[vmContext.stack.length - 1]
            });
            vmContext.stack[vmContext.stack.length - 3] = vmContext.stack[vmContext.stack.length - 3];
            vmContext.stack.length -= 2;
            break;
        case 18:
            var byte$0 = decodedBytecode[vmContext.programCounter];
            var byte$1 = decodedBytecode[vmContext.programCounter + 1];
            var byte$2 = decodedBytecode[vmContext.programCounter + 2] << 16 | (decodedBytecode[vmContext.programCounter + 3] << 8 | decodedBytecode[vmContext.programCounter + 4]);
            var byte$3 = decodedBytecode[vmContext.programCounter + 5];
            vmContext.programCounter += 6;
            var stack$0Pointer = vmContext.stack.length - 1;
            var stack$0 = vmContext.stack[vmContext.stack.length - 1];
            vmContext.registers.set(byte$0, stack$0);
            var stack$1Pointer = vmContext.stack.length - 2;
            var stack$1 = vmContext.stack[vmContext.stack.length - 2];
            vmContext.registers.set(byte$1, stack$1);
            var stackLength$0 = vmContext.stack.length - 2;
            vmContext.stack[stackLength$0] = byte$3;
            vmContext.stack[stackLength$0 + 1] = byte$2;
            break;
        case 59:
            var byte$0 = decodedBytecode[vmContext.programCounter] << 8 | decodedBytecode[vmContext.programCounter + 1];
            vmContext.programCounter += 2;
            vmContext.stack[vmContext.stack.length - 2] = createOpcodeFunction(byte$0, vmContext.stack[vmContext.stack.length - 1], vmContext.stack[vmContext.stack.length - 2], vmContext.registers);
            vmContext.stack.length -= 1;
            break;
        case 84:
            var rawString$0 = encodedStringArray[decodedBytecode[vmContext.programCounter] << 8 | decodedBytecode[vmContext.programCounter + 1]];
            vmContext.programCounter += 2;
            vmContext.stack[vmContext.stack.length] = rawString$0;
            break;
        case 87:
            
            vmContext.stack[vmContext.stack.length - 2] = vmContext.stack[vmContext.stack.length - 2][vmContext.stack[vmContext.stack.length - 1]];
            vmContext.stack.length -= 1;
            break;
        case 104:
            var byte$0 = decodedBytecode[vmContext.programCounter];
            vmContext.programCounter += 1;
            vmContext.stack[vmContext.stack.length] = byte$0;
            break;
        case 117:
            var byte$0 = decodedBytecode[vmContext.programCounter];
            vmContext.programCounter += 1;
            vmContext.stack[vmContext.stack.length] = vmContext.registers.get(byte$0);
            break;
        case 120:
            var byte$0 = decodedBytecode[vmContext.programCounter] << 16 | (decodedBytecode[vmContext.programCounter + 1] << 8 | decodedBytecode[vmContext.programCounter + 2]);
            var byte$1 = decodedBytecode[vmContext.programCounter + 3];
            vmContext.programCounter += 4;
            decodedBytecode[byte$0] = byte$1;
            break;
        case 128:
            var byte$0 = decodedBytecode[vmContext.programCounter];
            vmContext.programCounter += 1;
            vmContext.registers.set(byte$0, vmContext.stack[vmContext.stack.length - 1]);
            vmContext.stack.length -= 1;
            break;
        case 129:
            var byte$0 = decodedBytecode[vmContext.programCounter];
            var rawString$0 = encodedStringArray[decodedBytecode[vmContext.programCounter + 1] << 8 | decodedBytecode[vmContext.programCounter + 2]];
            vmContext.programCounter += 3;
            var array$0 = [];
            var stackLength$0 = vmContext.stack.length;
            vmContext.stack[stackLength$0] = array$0;
            vmContext.stack[stackLength$0 + 1] = byte$0;
            vmContext.stack[stackLength$0 + 2] = rawString$0;
            break;
        case 134:
            var byte$0 = decodedBytecode[vmContext.programCounter] << 8 | decodedBytecode[vmContext.programCounter + 1];
            vmContext.programCounter += 2;
            vmContext.stack[vmContext.stack.length] = byte$0;
            break;
        case 138:
            var byte$0 = decodedBytecode[vmContext.programCounter] << 8 | decodedBytecode[vmContext.programCounter + 1];
            vmContext.programCounter += 2;
            vmContext.stack[vmContext.stack.length] = byte$0;
            break;
        case 139:
            vmContext.programCounter = vmContext.reg.F;
            vmContext.opcodeHandlerCounter = vmContext.reg.K;   
            break;
        case 152:
            vmContext.stack[vmContext.stack.length - 2] = vmContext.stack[vmContext.stack.length - 2] < vmContext.stack[vmContext.stack.length - 1];
            vmContext.stack.length -= 1;
            break;
        case 187:
            var EK = decodedBytecode[vmContext.programCounter] << 8 | decodedBytecode[vmContext.programCounter + 1];
            vmContext.programCounter += 2;
            var Ey = vmContext.stack[vmContext.stack.length - 1];
            var Ep = Ey + "," + EK;
            var Ex = globalEmptyObj[Ep];
            if (typeof Ex !== "undefined") {
                vmContext.stack[vmContext.stack.length - 1] = Ex;
                return;
            }
            var Es = encodedStringArray[EK];
            var EZ = decodeString(Es);
            var Ej = decodeString(Ey);
            var Eo = EZ[0] + Ej[0] & 255;
            var EH = "";
            for (var Eq = 1; Eq < EZ.length; ++Eq) {
                EH += String.fromCharCode(Ej[Eq] ^ EZ[Eq] ^ Eo);
            }
            vmContext.stack[vmContext.stack.length - 1] = globalEmptyObj[Ep] = EH;
            break;
        case 188:
            var ET = encodedStringArray[decodedBytecode[vmContext.programCounter] << 8 | decodedBytecode[vmContext.programCounter + 1]];
            vmContext.programCounter += 2;
            if (!(ET in window)) {
                throw new ReferenceError(ET + " is not defined.");
            }
            vmContext.stack[vmContext.stack.length] = window[ET];
            break;
        case 211:
            var cy = decodedBytecode[vmContext.programCounter] << 16 | (decodedBytecode[vmContext.programCounter + 1] << 8 | decodedBytecode[vmContext.programCounter + 2]);
            var cp = decodedBytecode[vmContext.programCounter + 3];
            vmContext.programCounter += 4;
            vmContext.reg = {
                F: vmContext.programCounter,
                K: vmContext.opcodeHandlerCounter
            };
            vmContext.programCounter = cy;
            vmContext.opcodeHandlerCounter = cp;
            break;
        
        case 217:
            var cF = decodedBytecode[vmContext.programCounter];
            var ch = decodedBytecode[vmContext.programCounter + 1];
            vmContext.programCounter += 2;
            if (!vmContext.stack[vmContext.stack.length - 1]) {
                vmContext.programCounter = cF;
                vmContext.opcodeHandlerCounter = ch;
            }
            vmContext.stack.length -= 1;
            break;
        case 235:
            vmContext.programCounter = vmContext.stack[vmContext.stack.length - 1];
            vmContext.opcodeHandlerCounter = vmContext.stack[vmContext.stack.length - 2];
            vmContext.stack.length -= 2;
            break;
    }

}