/******************************************************************************
*	File		-	world_api.cpp
*	Author		-	Joey Pollack
*	Date		-	2022/11/21 (y/m/d)
*	Mod Date	-	2022/11/21 (y/m/d)
*	Description	-	The scripting api for the world interface
******************************************************************************/

#include "world_api.h"
#include "component_api.h"
#include <world/world.h>
#include <world/entity.h>
#include <utils/logger.h>
#include <utils/helpers.h>

#include <cstdarg>

namespace lunarium 
{
    WrenState WorldAPI::mScriptState;
    World* WorldAPI::mpWorld = nullptr;
    WorldAPI::ScriptEventHandles WorldAPI::mEventHandles;

    OpRes WorldAPI::Initialize(World* pWorld)
    {
        mpWorld = pWorld;

        mScriptState.Initialize().LogIfFailed(LogCategory::GAME_SYSTEM, "Failed to initialize the world script state");

        // Register foreign methods
        //mScriptState.RegisterForeignMethod({"WorldInterface", "WorldInterface", true, "GetComponent(_,_)", (WrenForeignMethodFn)&WorldAPI::GetVelocityComponent});

        // Register component foreign classes
        ComponentAPI::Initialize(mpWorld, mScriptState);

        // Load the component script
        WrenScript components;
        components.SetModuleName("Components");
        std::string code = File::ReadTextFile("components.wren");  // This will eventually move to internal data
        components.SetScriptCode(code);
        mScriptState.RunScript(&components);

        // Load the world interface script
        WrenScript world_interface;
        world_interface.SetModuleName("WorldInterface");
        code = File::ReadTextFile("world_interface.wren");  // This will eventually move to internal data
        world_interface.SetScriptCode(code);
        mScriptState.RunScript(&world_interface);

        

        // Get class and method handles
        mEventHandles.mWIHandle = mScriptState.GetWrenClassHandle("WorldInterface", "WorldInterface");
        mEventHandles.mWIInitMethod = mScriptState.GetWrenMethodHandle("Init()");
        mEventHandles.mWIDoOnLoadMethod = mScriptState.GetWrenMethodHandle("DoOnLoad()");
        mEventHandles.mWIDoOnUnloadMethod = mScriptState.GetWrenMethodHandle("DoOnUnload()");
        mEventHandles.mWIUpdateMethod = mScriptState.GetWrenMethodHandle("Update(_)");

        // Init the interface
        mScriptState.CallWrenMethod(mEventHandles.mWIInitMethod, mEventHandles.mWIHandle, {}, "WorldInterface.Init()");

        return OpRes::OK();
    }

    void WorldAPI::Shutdown()
    {
        mpWorld = nullptr;
    }


    void WorldAPI::RunScript(WrenScript& script)
    {
        mScriptState.RunScript(&script);
    }

    void WorldAPI::InvokeEvent(Event e, ...)
    {
        switch (e)
        {
            case Event::ON_LOAD: mScriptState.CallWrenMethod(mEventHandles.mWIDoOnLoadMethod, mEventHandles.mWIHandle, {}, "WorldInterface.DoOnLoad()"); break;
            case Event::ON_UNLOAD: mScriptState.CallWrenMethod(mEventHandles.mWIDoOnUnloadMethod, mEventHandles.mWIHandle, {}, "WorldInterface.DoOnUnload()"); break;
            case Event::ON_UPDATE:
            {
                va_list args;
                va_start(args, e);
                double dt = va_arg(args, double);
                
                mScriptState.CallWrenMethod(mEventHandles.mWIUpdateMethod, mEventHandles.mWIHandle, { {WrenParamType::WPT_DOUBLE, (double)dt} }, "WorldInterface.Update(dt)" );

                va_end(args);
            }
            break;
        }
    }

    /////////////////////////////////////////////////////////////////////
    //				SCRIPT API
    /////////////////////////////////////////////////////////////////////

    void WorldAPI::GetVelocityComponent(WrenVM* vm)
    {
        std::string str_entity_id = wrenGetSlotString(vm, 1);
        LUUID entity_id = std::stoull(str_entity_id);

        // More examples of creating foreign class instances
        // https://github.com/wren-lang/wren/issues/1062


    }

    /////////////////////////////////////////////////////////////////////
    //				FOREIGN CLASSES
    /////////////////////////////////////////////////////////////////////
    
    
}