#include "DeerStudio/EditorEngine.h"
#include "DeerStudio/EditorEngine/ErrorHandle.h"
#include "DeerStudio/EditorEngine/API.h"
#include "DeerStudio/EditorEngine/API_Registration/API_Registration.h"

#include "scripthandle.h"
#include "scriptany.h"
#include "angelscript.h"
#include "imgui.h"

namespace Deer {
    void EditorEngine::registerUIFunctions() {

        scriptEngine->SetDefaultNamespace("UI");
        REGISTER_GLOBAL_FUNC("bool button(const string& in)", button);
        REGISTER_GLOBAL_FUNC("bool buttonCenter(const string&in)", buttonCenter);
        REGISTER_GLOBAL_FUNC("bool buttonEnd(const string&in)", buttonEnd);
        REGISTER_GLOBAL_FUNC("bool checkbox(const string& in, bool)", checkbox);
        REGISTER_GLOBAL_FUNC("bool checkboxDisabled(const string& in, bool)", checkboxDisabled);
        REGISTER_GLOBAL_FUNC("void drawFrameBuffer(FrameBuffer, int, int)", drawFrameBuffer);
        REGISTER_GLOBAL_FUNC("void drawFrameBufferCentered(FrameBuffer, int, int)", drawFrameBufferCentered);
        REGISTER_GLOBAL_FUNC("void drawIcon(const string& in, int)", drawIcon);
        REGISTER_GLOBAL_FUNC("void drawIconCentered(const string& in, int)", drawIconCentered);
        REGISTER_GLOBAL_FUNC("bool inputText(const string& in, const string& in, string& out)", inputText);
        REGISTER_GLOBAL_FUNC("bool isItemClicked(int)", isItemClicked);
        REGISTER_GLOBAL_FUNC("bool isMouseDoubleClicked(int)", isMouseDoubleClicked);
        REGISTER_GLOBAL_FUNC("float magicSlider(const string& in, float, float)", magicSlider);
        REGISTER_GLOBAL_FUNC("vec3 magicSlider3(const string& in, vec3, float)", magicSlider3);
        REGISTER_GLOBAL_FUNC("bool menuItem(const string& in)", menuItem);
        REGISTER_GLOBAL_FUNC("void menuItemDisabled(const string& in)", menuItemDisabled);
        REGISTER_GLOBAL_FUNC("void menuSpace(const string& in, any@+, ReciverFunc@+)", menuSpace);
        REGISTER_GLOBAL_FUNC("void sameline()", sameline);
        REGISTER_GLOBAL_FUNC("void separator()", separator);
        REGISTER_GLOBAL_FUNC("void space()", space);
        REGISTER_GLOBAL_FUNC("void space(int, int = 10)", space_params);
        REGISTER_GLOBAL_FUNC("void text(const string& in)", text);
        REGISTER_GLOBAL_FUNC("void textCenter(const string& in)", textCenter);
        REGISTER_GLOBAL_FUNC("void textColor(float, float, float, const string& in)", textColor);
        REGISTER_GLOBAL_FUNC("void textEnd(const string& in)", textEnd);
        REGISTER_GLOBAL_FUNC("void title(const string&in)", title);
        REGISTER_GLOBAL_FUNC("void titleCenter(const string&in)", titleCenter);
        REGISTER_GLOBAL_FUNC("void titleCenterY(const string&in, int)", titleCenterY);
        REGISTER_GLOBAL_FUNC("void titleEnd(const string&in)", titleEnd);
        REGISTER_GLOBAL_FUNC("bool isKeyDown(key)", isKeyDown);
        REGISTER_GLOBAL_FUNC("bool isKeyPressed(key)", isKeyPressed);
        REGISTER_GLOBAL_FUNC("bool isMouseDraggin(key)", isMouseDraggin);
        REGISTER_GLOBAL_FUNC("bool isPannelActive()", isPannelActive);
        REGISTER_GLOBAL_FUNC("float getMouseDragDeltaX()", getMouseDragDeltaX);
        REGISTER_GLOBAL_FUNC("float getMouseDragDeltaY()", getMouseDragDeltaY);
        REGISTER_GLOBAL_FUNC("float getMouseDeltaX()", getMouseDeltaX);
        REGISTER_GLOBAL_FUNC("float getMouseDeltaY()", getMouseDeltaY);
        REGISTER_GLOBAL_FUNC("int getAvailableSizeX()", getAvailableSizeX);
        REGISTER_GLOBAL_FUNC("int getAvailableSizeY()", getAvailableSizeY);
        REGISTER_GLOBAL_FUNC("void disablePannelPadding(bool)", disablePannelPadding);
        REGISTER_GLOBAL_FUNC("int sliderInt(string&in, int, int, int)", sliderInt);
        REGISTER_GLOBAL_FUNC("float slider(string&in, float, float, float)", slider);
        scriptEngine->SetDefaultNamespace("");
    }

    void EditorEngine::registerUIStructs() {
        AS_CHECK(scriptEngine->RegisterEnum("key"));

        AS_CHECK(scriptEngine->RegisterEnumValue("key", "A", ImGuiKey_A));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "B", ImGuiKey_B));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "C", ImGuiKey_C));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "D", ImGuiKey_D));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "E", ImGuiKey_E));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "F", ImGuiKey_F));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "G", ImGuiKey_G));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "H", ImGuiKey_H));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "I", ImGuiKey_I));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "J", ImGuiKey_J));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K", ImGuiKey_K));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "L", ImGuiKey_L));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "M", ImGuiKey_M));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "N", ImGuiKey_N));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "O", ImGuiKey_O));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "P", ImGuiKey_P));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Q", ImGuiKey_Q));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "R", ImGuiKey_R));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "S", ImGuiKey_S));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "T", ImGuiKey_T));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "U", ImGuiKey_U));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "V", ImGuiKey_V));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "W", ImGuiKey_W));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "X", ImGuiKey_X));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Y", ImGuiKey_Y));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Z", ImGuiKey_Z));

        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K0", ImGuiKey_0));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K1", ImGuiKey_1));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K2", ImGuiKey_2));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K3", ImGuiKey_3));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K4", ImGuiKey_4));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K5", ImGuiKey_5));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K6", ImGuiKey_6));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K7", ImGuiKey_7));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K8", ImGuiKey_8));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "K9", ImGuiKey_9));

        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Tab", ImGuiKey_Tab));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Enter", ImGuiKey_Enter));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Escape", ImGuiKey_Escape));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Backspace", ImGuiKey_Backspace));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Space", ImGuiKey_Space));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Delete", ImGuiKey_Delete));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Insert", ImGuiKey_Insert));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Home", ImGuiKey_Home));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "End", ImGuiKey_End));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "PageUp", ImGuiKey_PageUp));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "PageDown", ImGuiKey_PageDown));
        
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Right", ImGuiKey_RightArrow));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Up", ImGuiKey_UpArrow));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Down", ImGuiKey_DownArrow));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "Left", ImGuiKey_LeftArrow));
        
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "RightCtrl", ImGuiKey_RightCtrl));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "LeftShift", ImGuiKey_LeftShift));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "RightShift", ImGuiKey_RightShift));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "LeftAlt", ImGuiKey_LeftAlt));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "RightAlt", ImGuiKey_RightAlt));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "LeftSuper", ImGuiKey_LeftSuper));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "RightSuper", ImGuiKey_RightSuper));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "LeftCtrl", ImGuiKey_LeftCtrl));

        AS_CHECK(scriptEngine->RegisterEnumValue("key", "MouseLeft", ImGuiKey_MouseLeft));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "MouseRight", ImGuiKey_MouseRight));
        AS_CHECK(scriptEngine->RegisterEnumValue("key", "MouseMiddle", ImGuiKey_MouseMiddle));
    }
}

/*
enum ImGuiKey : int
{
    // Keyboard
    ImGuiKey_None = 0,
    ImGuiKey_Tab = 512,             // == ImGuiKey_NamedKey_BEGIN
    ImGuiKey_LeftArrow,
    ImGuiKey_RightArrow,
    ImGuiKey_UpArrow,
    ImGuiKey_DownArrow,
    ImGuiKey_PageUp,
    ImGuiKey_PageDown,
    ImGuiKey_Home,
    ImGuiKey_End,
    ImGuiKey_Insert,
    ImGuiKey_Delete,
    ImGuiKey_Backspace,
    ImGuiKey_Space,
    ImGuiKey_Enter,
    ImGuiKey_Escape,
    ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper,
    ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper,
    ImGuiKey_Menu,
    ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9,
    ImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J,
    ImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T,
    ImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z,
    ImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6,
    ImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12,
    ImGuiKey_Apostrophe,        // '
    ImGuiKey_Comma,             // ,
    ImGuiKey_Minus,             // -
    ImGuiKey_Period,            // .
    ImGuiKey_Slash,             // /
    ImGuiKey_Semicolon,         // ;
    ImGuiKey_Equal,             // =
    ImGuiKey_LeftBracket,       // [
    ImGuiKey_Backslash,         // \ (this text inhibit multiline comment caused by backslash)
    ImGuiKey_RightBracket,      // ]
    ImGuiKey_GraveAccent,       // `
    ImGuiKey_CapsLock,
    ImGuiKey_ScrollLock,
    ImGuiKey_NumLock,
    ImGuiKey_PrintScreen,
    ImGuiKey_Pause,
    ImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4,
    ImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9,
    ImGuiKey_KeypadDecimal,
    ImGuiKey_KeypadDivide,
    ImGuiKey_KeypadMultiply,
    ImGuiKey_KeypadSubtract,
    ImGuiKey_KeypadAdd,
    ImGuiKey_KeypadEnter,
    ImGuiKey_KeypadEqual,

    // Gamepad (some of those are analog values, 0.0f to 1.0f)                          // NAVIGATION ACTION
    // (download controller mapping PNG/PSD at http://dearimgui.org/controls_sheets)
    ImGuiKey_GamepadStart,          // Menu (Xbox)      + (Switch)   Start/Options (PS)
    ImGuiKey_GamepadBack,           // View (Xbox)      - (Switch)   Share (PS)
    ImGuiKey_GamepadFaceLeft,       // X (Xbox)         Y (Switch)   Square (PS)        // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows)
    ImGuiKey_GamepadFaceRight,      // B (Xbox)         A (Switch)   Circle (PS)        // Cancel / Close / Exit
    ImGuiKey_GamepadFaceUp,         // Y (Xbox)         X (Switch)   Triangle (PS)      // Text Input / On-screen Keyboard
    ImGuiKey_GamepadFaceDown,       // A (Xbox)         B (Switch)   Cross (PS)         // Activate / Open / Toggle / Tweak
    ImGuiKey_GamepadDpadLeft,       // D-pad Left                                       // Move / Tweak / Resize Window (in Windowing mode)
    ImGuiKey_GamepadDpadRight,      // D-pad Right                                      // Move / Tweak / Resize Window (in Windowing mode)
    ImGuiKey_GamepadDpadUp,         // D-pad Up                                         // Move / Tweak / Resize Window (in Windowing mode)
    ImGuiKey_GamepadDpadDown,       // D-pad Down                                       // Move / Tweak / Resize Window (in Windowing mode)
    ImGuiKey_GamepadL1,             // L Bumper (Xbox)  L (Switch)   L1 (PS)            // Tweak Slower / Focus Previous (in Windowing mode)
    ImGuiKey_GamepadR1,             // R Bumper (Xbox)  R (Switch)   R1 (PS)            // Tweak Faster / Focus Next (in Windowing mode)
    ImGuiKey_GamepadL2,             // L Trig. (Xbox)   ZL (Switch)  L2 (PS) [Analog]
    ImGuiKey_GamepadR2,             // R Trig. (Xbox)   ZR (Switch)  R2 (PS) [Analog]
    ImGuiKey_GamepadL3,             // L Stick (Xbox)   L3 (Switch)  L3 (PS)
    ImGuiKey_GamepadR3,             // R Stick (Xbox)   R3 (Switch)  R3 (PS)
    ImGuiKey_GamepadLStickLeft,     // [Analog]                                         // Move Window (in Windowing mode)
    ImGuiKey_GamepadLStickRight,    // [Analog]                                         // Move Window (in Windowing mode)
    ImGuiKey_GamepadLStickUp,       // [Analog]                                         // Move Window (in Windowing mode)
    ImGuiKey_GamepadLStickDown,     // [Analog]                                         // Move Window (in Windowing mode)
    ImGuiKey_GamepadRStickLeft,     // [Analog]
    ImGuiKey_GamepadRStickRight,    // [Analog]
    ImGuiKey_GamepadRStickUp,       // [Analog]
    ImGuiKey_GamepadRStickDown,     // [Analog]

    // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls)
    // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API.
    ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY,

    // [Internal] Reserved for mod storage
    ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper,
    ImGuiKey_COUNT,

    // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls)
    // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing
    //   them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc.
    // - Code polling every key (e.g. an interface to detect a key press for input mapping) might want to ignore those
    //   and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiMod_Ctrl).
    // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys.
    //   In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and
    //   backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user...
    ImGuiMod_None                   = 0,
    ImGuiMod_Ctrl                   = 1 << 12, // Ctrl
    ImGuiMod_Shift                  = 1 << 13, // Shift
    ImGuiMod_Alt                    = 1 << 14, // Option/Menu
    ImGuiMod_Super                  = 1 << 15, // Cmd/Super/Windows
    ImGuiMod_Shortcut               = 1 << 11, // Alias for Ctrl (non-macOS) _or_ Super (macOS).
    ImGuiMod_Mask_                  = 0xF800,  // 5-bits

    // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array.
    // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE)
    ImGuiKey_NamedKey_BEGIN         = 512,
    ImGuiKey_NamedKey_END           = ImGuiKey_COUNT,
    ImGuiKey_NamedKey_COUNT         = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN,
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
    ImGuiKey_KeysData_SIZE          = ImGuiKey_NamedKey_COUNT,          // Size of KeysData[]: only hold named keys
    ImGuiKey_KeysData_OFFSET        = ImGuiKey_NamedKey_BEGIN,          // First key stored in io.KeysData[0]. Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET).
#else
    ImGuiKey_KeysData_SIZE          = ImGuiKey_COUNT,                   // Size of KeysData[]: hold legacy 0..512 keycodes + named keys
    ImGuiKey_KeysData_OFFSET        = 0,                                // First key stored in io.KeysData[0]. Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET).
#endif

#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    ImGuiKey_ModCtrl = ImGuiMod_Ctrl, ImGuiKey_ModShift = ImGuiMod_Shift, ImGuiKey_ModAlt = ImGuiMod_Alt, ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89
    ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter,    // Renamed in 1.87
#endif
}*/