import {il2cppApi} from "../il2cppApi";
import {log, LogColor, logColor} from "../../logger";
import {soName} from "../../config";

let il2CppImageArray = new Array();
let il2cppBaseAddr = undefined;
let needLog =false;
let methodAddrMap =new Map();
export var Il2cppHackerApi = {

    getGameObjectName: function (addr) {


    },

    getMethodAddr(Il2cppImageName, spaceze, className, methodName, methodCount) {
        //判断缓存是否有
        let cache = getCache(Il2cppImageName,spaceze,className,methodName,methodCount);
        if (cache!==undefined){
            return cache;
        }
        let il2cppImage = this.getTargetCppImage(Il2cppImageName);

        let il2CppClass = il2cppApi.il2cpp_class_from_name(il2cppImage, spaceze, className);
        // log("il2cppClass:" + il2CppClass.namespaze() + " name:" + il2CppClass.name());
        let methodInfo = il2cppApi.il2cpp_class_get_method_from_name(il2CppClass, methodName, methodCount);
        if (il2cppBaseAddr === undefined) {
            il2cppBaseAddr = Process.findModuleByName(soName);
        }
        if (needLog){
            logColor("-------------------------------------start---------------------------------------------------------", LogColor.RED);
        }
        let addr;
        let  number;
        let methodPointer;
        if (!methodInfo.isNull()) {
             methodPointer = methodInfo.getMethodPointer();
             number = methodPointer - il2cppBaseAddr.base;
            addr = "0x" + number.toString(16).toUpperCase();
            if (spaceze!==""){
                let key = getKey(Il2cppImageName,spaceze,className,methodName,methodCount);
                methodAddrMap.set(key,methodPointer);
            }
        } else {
            addr = "0x0";
            number=0;
            methodPointer=0;
        }
        if (!needLog){
            return methodPointer;
        }
        logColor(" Dll:"+Il2cppImageName,LogColor.C97);
        logColor(" class:"+spaceze+"."+il2CppClass.name(),LogColor.C97);
        logColor(" methodPointer offset in IDA:" + addr,LogColor.C97);
        let methodContent;
        //返回类型
        let returnType = methodInfo.getReturnType();
        let return_cls = il2cppApi.il2cpp_class_from_type(returnType);
        let name1 = return_cls.name();
        if (name1.indexOf("`") !== -1) {
            let split = name1.split("`");
            name1 = split[0];
            name1 = name1 + return_cls.getGenericName();
        }
        methodContent =   name1 + " " + methodInfo.name() + "(";
        let paramCount = methodInfo.getParamCount();
        // log("paramCount:" + paramCount);
        if (paramCount > 0) {
            for (let i = 0; i < paramCount; i++) {
                let paramType = methodInfo.getParam(i);
                let paramCls = il2cppApi.il2cpp_class_from_type(paramType);
                let name = paramCls.name();
                //获取泛型
                if (name.indexOf("`") !== -1) {
                    let split = name.split("`");
                    name = split[0];
                    name = name + paramCls.getGenericName();
                }
                methodContent = methodContent + name + " " + methodInfo.getParamName(i);
                if (i + 1 !== paramCount) {
                    methodContent = methodContent + ", ";
                } else {
                    methodContent = methodContent + ") { }\n";
                }
            }
        } else {
            methodContent = methodContent + "){ }\n";
        }
        logColor(" "+methodContent,LogColor.C97);
        logColor("-------------------------------------end----------------------------------------------------------", LogColor.RED);
        return methodPointer;
    },
    getTargetCppImage(name) {
        let cppImageArray = this.getCppImageArray();
        if (cppImageArray.length > 0) {
            for (let i = 0; i < cppImageArray.length; i++) {
                let Il2CppImage = cppImageArray[i];
                let nameNoExt = Il2CppImage.name();
                if (nameNoExt === name) {
                    return Il2CppImage;
                }
            }
        }
    },
    getCppImageArray: function () {
        if (il2CppImageArray.length !== 0) {
            return il2CppImageArray;
        }
        let domain = il2cppApi.il2cpp_domain_get();
        let size_t = Memory.alloc(Process.pointerSize);
        //可能还没加载
        let assemblies = il2cppApi.il2cpp_domain_get_assemblies(domain, size_t);
        let assemblies_count = size_t.readInt();
        log("assemblies_count:" + assemblies_count);

        for (let i = 0; i < assemblies_count; i++) {

            let assembly = assemblies.add(Process.pointerSize * i).readPointer();
            let Il2CppImage = il2cppApi.il2cpp_assembly_get_image(assembly);
            // log(" name:" + Il2CppImage.name());
            il2CppImageArray.push(Il2CppImage);
        }
        return il2CppImageArray;
    }
}
function  getCache(Il2cppImageName,spaceze,className,methodName,methodCount){

    let key = getKey(Il2cppImageName,spaceze,className,methodName,methodCount);
    let newVar = methodAddrMap.get(key);
    if (newVar===undefined || newVar===null){
        return  undefined;
    }else {
        return newVar;
    }

}

function  getKey(Il2cppImageName,spaceze,className,methodName,methodCount){
    return Il2cppImageName + "_" + spaceze + "_" + className + "_" + methodName + "_" + methodCount;
}