#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
#include "frida-gum.h"

typedef void *(*__GetGameManagerVoid)();
static SQInteger GameManager_GameManager(HSQUIRRELVM v)
{
    void *GameManager = ((__GetGameManagerVoid)0x080CC18E)();
    sq_pushuserpointer(v, GameManager);
    return 1;
}
typedef void *(*__GameManagerByThis)(void *GameManager);
static SQInteger GameManager_GetParty(HSQUIRRELVM v)
{
    SQUserPointer P;
    sq_getuserpointer(v, 2, &P);
    void *CParty = ((__GameManagerByThis)0x08294E10)(P);
    if (CParty)
        sq_pushuserpointer(v, CParty);
    else
        sq_pushinteger(v, 0);
    return 1;
}

typedef int (*cdeclCall2P)(int *a1, int a2);
static cdeclCall2P SkillSlot__get_skillslot_buf = (cdeclCall2P)0x086067DE;
static cdeclCall2P SkillSlot__gcheckComboSkillInsertQuickSlot = (cdeclCall2P)0x08608D58;
#define RDWORD(addr, offset) (*(DWORD *)((char *)(addr) + (offset)))
int __attribute__((cdecl)) hookCSkill__reform_ui_group_no(int *thisP, int *skillClassP, bool isTpSkill, int a4)
{
    int p = (int)skillClassP;
    if (RDWORD(skillClassP, -0x60) == 197)
    {
        // cout << " fix skill197 class to 4!" << endl;
        *skillClassP = 4;
    }
    return 0;
}

int __attribute__((cdecl)) hookSkillSlot__get_skillslot_group(int *thisP, int slot)
{
    // DWORD retAddr = (DWORD)gum_invocation_context_get_return_address(NULL);
    // cout<< retAddr << " get_skillslot_group:" << slot << endl;
    if (slot < 8 || slot >= 198)
        return -1;
    else if (slot >= 160)
        return 4;
    else if (slot >= 122)
        return 3;
    else if (slot >= 84)
        return 2;
    else if (slot >= 46)
        return 1;
    else
        return 0;
}

int __attribute__((cdecl)) hookSkillSlot__get_skillslot_no(int *thisP, int skillId, int group, int slot, char is_active_skill)
{
    if (!thisP || !*thisP)
        return -1;
    BYTE *buf = (BYTE *)SkillSlot__get_skillslot_buf(thisP, slot);
    if (!buf)
        return -1;
    if (is_active_skill && SkillSlot__gcheckComboSkillInsertQuickSlot(thisP, skillId))
    {
        int end = skillId ? 7 : 5;
        for (int i = 0; i <= end; ++i)
        {
            if (buf[2 * i] == skillId)
            {
                return i;
            }
        }
        for (int i = 198; i <= 203; ++i)
        {
            if (buf[2 * i] == skillId)
            {
                return i;
            }
        }
    }
    int pos = 8 + group * 38;
    for (int i = 0; i < 38; ++i)
    {
        if (buf[2 * (i + pos)] == skillId)
        {
            return i + pos;
        }
    }
    return -1;
}

int __attribute__((cdecl)) hookSkillSlot__get_skillslot_no2(int *thisP, BYTE *buf, int skillId, int group, char is_active_skill)
{
    if (!thisP || !*thisP || !buf)
        return -1;
    if (is_active_skill)
    {
        int end = skillId ? 7 : 5;
        for (int i = 0; i <= end; ++i)
        {
            if (buf[2 * i] == skillId)
            {
                return i;
            }
        }
        for (int i = 198; i <= 203; ++i)
        {
            if (buf[2 * i] == skillId)
            {
                return i;
            }
        }
    }
    int pos = 8 + group * 38;
    for (int i = 0; i < 38; ++i)
    {
        if (buf[2 * (i + pos)] == skillId)
        {
            return i + pos;
        }
    }
    return -1;
}

static SQInteger GameManager_FixA4Skill(HSQUIRRELVM vm)
{
    GumInterceptor *v = gum_interceptor_obtain();
    gum_interceptor_begin_transaction(v);
    gum_interceptor_replace_fast(v, (gpointer)0x083507E8, (gpointer)hookCSkill__reform_ui_group_no, NULL);
    gum_interceptor_replace_fast(v, (gpointer)0x086049FC, (gpointer)hookSkillSlot__get_skillslot_group, NULL);
    gum_interceptor_replace_fast(v, (gpointer)0x08604A86, (gpointer)hookSkillSlot__get_skillslot_no, NULL);
    gum_interceptor_replace_fast(v, (gpointer)0x08607DBA, (gpointer)hookSkillSlot__get_skillslot_no2, NULL);
    gum_interceptor_end_transaction(v);
    return 0;
}

static SQInteger register_GameManager_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
    sq_pushroottable(v);
    sq_pushstring(v, fname, -1);
    sq_newclosure(v, f, 0); // create a new function
    sq_newslot(v, -3, SQFalse);
    sq_pop(v, 1); // pops the root table
}

static void RegisterGameManager(HSQUIRRELVM v)
{
    // 获得GameManager对象
    register_GameManager_func(v, GameManager_GameManager, _SC("Sq_GameManager_GameManager"));
    // 获得队伍对象
    register_GameManager_func(v, GameManager_GetParty, _SC("Sq_GameManager_GetParty"));
    // 修复A4技能
    register_GameManager_func(v, GameManager_FixA4Skill, _SC("Sq_FixA4Skill"));
}