#include "client.h"

#include "interop/imports.h"

#include <iostream>

namespace fugg
{
    // Emscripten runtime:
    // 1. Pre-run
    // 2. Init runtime
    // 3. Pre-main
    // 4. Call main
    // 5. Post-run

    using namespace interop;

    using wasm::kMemory;
    using wasm::kTable;

    Client::Client() {
        // 1. Pre-run: There are no pre-runs in this binary.
        // 2. Init runtime: `___wasm_call_ctors` is added to on init runtime.
        (*import::__wasm_call_ctors)();               
    }

    Client& Client::instance() {
        static bool initialised = false;
        if(!initialised) {
            // Initialise the WebAssembly runtime.
            wasm_rt_init();
            // Initialise the client.
            import::init();
            // Only init the module once.
            initialised = true;
        }
        // Constructor will be called.
        static Client instance;
        // Whole module is initialised now.
        return instance;
    }    

    void Client::initialise() {

    }

    int Client::main() const {
        // 3. Pre-main: There are no pre-mains in this binary.
        // 4. Call main: `_main` is main in the binary.
        // TODO: Fix arguments.
        return (*import::_main)(0, 0);
    }
}

#include <unordered_set>
#include <unordered_map>
#include <vector>

#include <string>
#include <memory>

void before_main_loop() {
    auto& client = fugg::Client::instance(); 
}

#include "interop/flyff.h"

void after_main_loop() {
    // std::string test;

    // auto& music_properties = fugg::module_ref<fugg::Vector<flyff::MusicProperty>>(0x00034f7c);
    // auto& item_properties = fugg::module_ref<fugg::Vector<flyff::ItemProperty>>(0x00035194);
    
    // for(auto& item : item_properties) {
    //     std::cout << item.some_string->c_str() << std::endl;
    // }

    // auto& item_properties = fugg::module_ref<fugg::Vector<flyff::ItemProperty>>(0x00035194);
    // std::cout << "Expecting " << reinterpret_cast<void*>(fugg::wasm::kMemory.address_of(0x00035194)) << std::endl;

    // std::cout << "Item has " << item_properties->size() << std::endl;

    // std::cout << "There are " << item_properties->size() << " item properties." << std::endl;
    // for(const auto& item : *item_properties) {
    //     std::cout << "Item with id " << item.translation_tag.tag << std::endl;        
    // }

    // auto test = reinterpret_cast<Pointer<int>*>(0x00035194);
    
    
    
    

    // std::cout << "Test is at " << reinterpret_cast<void*>(test->to_intptr_t()) << std::endl;

    // if((void*)test == (void*)0x00035194) {
    //     std::cout << "Test is at the right address!" << std::endl;
    // }

    // auto vector_location = fugg::ModulePointer<uintptr_t> { 0x00035194 };
    // auto ptr = fugg::ModulePointer<ThisPointerTest> { 0x00035194 };

    // std::cout << "vector_location is at " << reinterpret_cast<void*>(0x00035194) << std::endl;
    // std::cout << "ptr is at " << 

    // auto raw = new RawVector {
    //     .begin          = **fugg::ModulePointer<fugg::ModulePointer<uintptr_t>> { 0x00035194 + 0 },
    //     .end            = **fugg::ModulePointer<fugg::ModulePointer<uintptr_t>> { 0x00035194 + 4 },
    //     .end_capacity   = **fugg::ModulePointer<fugg::ModulePointer<uintptr_t>> { 0x00035194 + 8 },
    // };

    // auto unique = std::unique_ptr<RawVector>(raw);
    // auto vec = reinterpret_cast<std::vector<flyff::ItemProperty>*>(raw);

    // auto unique = std::unique_ptr<std::vector<flyff::ItemProperty>>(vec);

    // std::cout << "There are " << unique->size() << " items!" << std::endl;

    // Probably deconstructed here.

    // std::cout << "Constructed raw. Call raw->temp..." << std::endl;

    // std::cout << raw->temp << std::endl;

    // std::cout << "Done calling raw->temp" << std::endl;




}