#pragma once
#include <PSX/System/syscalls.hpp>

namespace JabyEngine {
    struct Thread {
        using Handle = SysCall::ThreadHandle;

        static constexpr uint32_t idx_from_handle(SysCall::ThreadHandle thread) {
            return thread & 0xFFFF;
        }

        static uintptr_t get_pic_of(Handle handle) {
            return table_of_tables.threads[idx_from_handle(handle)].epc;
        }

        template<size_t N>
        static Handle create(void(*function)(uint32_t), uint32_t(&stack)[N]) {
            return SysCall::OpenThread(reinterpret_cast<void(*)()>(function), &stack[N - 1], SysCall::get_gp());
        }

        static void set_kernel_mode_for(SysCall::ThreadHandle handle) {
            table_of_tables.threads[idx_from_handle(handle)].sr = 0x0;
        }

        static void set_user_mode_for(SysCall::ThreadHandle handle) {
            table_of_tables.threads[idx_from_handle(handle)].sr = 0x40000404;
        }
    };

    struct CurrentThread {
        static uintptr_t get_pic() {
            return table_of_tables.processes->current_tcb->epc;
        }

        static void force_a0(uint32_t a0) {
            table_of_tables.processes->current_tcb->reg[4] = a0;
        }

        static bool is_me(Thread::Handle handle) {
            return table_of_tables.processes->current_tcb == &table_of_tables.threads[Thread::idx_from_handle(handle)];
        }

        static void replace_with(Thread::Handle handle) {
            table_of_tables.processes->current_tcb = &table_of_tables.threads[Thread::idx_from_handle(handle)];
        }
    };

    struct MainThread {
        static constexpr const Thread::Handle Handle = 0xFF000000;

        static uintptr_t get_pic() {
            return table_of_tables.threads[0].epc;
        }
    };
}