// IAEngine: 2D Game Engine by IA
// Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#pragma once

#include <IACore/Exception.hpp>
#include <IACore/Logger.hpp>
#include <IACore/Map.hpp>
#include <IACore/Memory.hpp>
#include <IACore/String.hpp>
#include <IACore/Vector.hpp>

#include <IAEngine/glm/ext/matrix_clip_space.hpp>
#include <IAEngine/glm/ext/matrix_transform.hpp>
#include <IAEngine/glm/ext/scalar_constants.hpp>
#include <IAEngine/glm/mat4x4.hpp>
#include <IAEngine/glm/vec2.hpp>
#include <IAEngine/glm/vec3.hpp>
#include <IAEngine/glm/vec4.hpp>

#include <chrono>

#define IAE_LOG_TAG "IAE"

#define IAE_LOG_INFO(...) ia::Logger::Info(IAE_LOG_TAG, __VA_ARGS__)
#define IAE_LOG_WARN(...) ia::Logger::Warn(IAE_LOG_TAG, __VA_ARGS__)
#define IAE_LOG_ERROR(...) ia::Logger::Error(IAE_LOG_TAG, __VA_ARGS__)
#define IAE_LOG_SUCCESS(...) ia::Logger::Success(IAE_LOG_TAG, __VA_ARGS__)

namespace ia::iae
{
    using Handle = INT64;
    STATIC CONSTEXPR Handle INVALID_HANDLE = -1;

    using Vec2 = glm::vec2;
    using Vec3 = glm::vec3;
    using Vec4 = glm::vec4;
    using IVec2 = glm::ivec2;
    using IVec3 = glm::ivec3;
    using IVec4 = glm::ivec4;
    using Mat4 = glm::mat4;

    struct TimePeriod
    {
        TimePeriod()
        {
        }

        TimePeriod(IN INT32 value, IN INT32 randomAdjustment)
        {
            SetValue(value);
            SetRandomAdjustment(randomAdjustment);
        }

        VOID SetValue(IN INT32 value)
        {
            m_value = value;
        }

        VOID SetRandomAdjustment(IN INT32 adjustment)
        {
            m_randomAdjustment = adjustment;
        }

        FLOAT32 GetValue() CONST;

      private:
        INT32 m_value{};
        INT32 m_randomAdjustment{};
    };

    struct ImageView
    {
        Handle Image{};
        Vec4 Scissor{};
    };

    struct SoundView
    {
        Handle Sound{};
        INT32 LoopTimes{};
        TimePeriod LoopDelay{};
    };

    struct GeometryVertex
    {
        Vec2 Position{};
        Vec2 TexCoord{};
        Vec4 Color{};
    };

    enum class Direction : UINT8 {
        NONE = 255,
        DOWN = 0,
        DOWN_LEFT,
        LEFT,
        UP_LEFT,
        UP,
        UP_RIGHT,
        RIGHT,
        DOWN_RIGHT
    };

    struct Color
    {
        UINT8 R{0xFF};
        UINT8 G{0xFF};
        UINT8 B{0xFF};
        UINT8 A{0xFF};

        Vec4 GetAsFloatVec() CONST
        {
            return {(FLOAT32) R / 255.0f, (FLOAT32) G / 255.0f, (FLOAT32) B / 255.0f, (FLOAT32) A / 255.0f};
        }

        Color operator+(IN CONST Color &other) CONST
        {
            return Color{(UINT8) (R + other.R), (UINT8) (G + other.G), (UINT8) (B + other.B), (UINT8) (A + other.A)};
        }

        Color operator-(IN CONST Color &other) CONST
        {
            return Color{(UINT8) (R - other.R), (UINT8) (G - other.G), (UINT8) (B - other.B), (UINT8) (A - other.A)};
        }

        Color operator*(IN FLOAT32 v) CONST
        {
            return Color{(UINT8) (R * v), (UINT8) (G * v), (UINT8) (B * v), (UINT8) (A * v)};
        }
    };

    /* Adopted from SDL3 */
    enum class InputKey : UINT8
    {
        UNKNOWN = 0,
        A = 4,
        B = 5,
        C = 6,
        D = 7,
        E = 8,
        F = 9,
        G = 10,
        H = 11,
        I = 12,
        J = 13,
        K = 14,
        L = 15,
        M = 16,
        N = 17,
        O = 18,
        P = 19,
        Q = 20,
        R = 21,
        S = 22,
        T = 23,
        U = 24,
        V = 25,
        W = 26,
        X = 27,
        Y = 28,
        Z = 29,

        N1 = 30,
        N2 = 31,
        N3 = 32,
        N4 = 33,
        N5 = 34,
        N6 = 35,
        N7 = 36,
        N8 = 37,
        N9 = 38,
        N0 = 39,

        RETURN = 40,
        ESCAPE = 41,
        BACKSPACE = 42,
        TAB = 43,
        SPACE = 44,

        MINUS = 45,
        EQUALS = 46,
        LEFTBRACKET = 47,
        RIGHTBRACKET = 48,
        BACKSLASH = 49,
        NONUSHASH = 50,
        SEMICOLON = 51,
        APOSTROPHE = 52,
        GRAVE = 53,
        COMMA = 54,
        PERIOD = 55,
        SLASH = 56,

        CAPSLOCK = 57,

        F1 = 58,
        F2 = 59,
        F3 = 60,
        F4 = 61,
        F5 = 62,
        F6 = 63,
        F7 = 64,
        F8 = 65,
        F9 = 66,
        F10 = 67,
        F11 = 68,
        F12 = 69,

        K_PRINTSCREEN = 70,
        K_SCROLLLOCK = 71,
        K_PAUSE = 72,
        K_INSERT = 73,
        K_HOME = 74,
        K_PAGEUP = 75,
        K_DELETE = 76,
        K_END = 77,
        K_PAGEDOWN = 78,
        K_RIGHT = 79,
        K_LEFT = 80,
        K_DOWN = 81,
        K_UP = 82,

        NUMLOCKCLEAR = 83,
        KP_DIVIDE = 84,
        KP_MULTIPLY = 85,
        KP_MINUS = 86,
        KP_PLUS = 87,
        KP_ENTER = 88,
        KP_1 = 89,
        KP_2 = 90,
        KP_3 = 91,
        KP_4 = 92,
        KP_5 = 93,
        KP_6 = 94,
        KP_7 = 95,
        KP_8 = 96,
        KP_9 = 97,
        KP_0 = 98,
        KP_PERIOD = 99,

        NONUSBACKSLASH = 100,
        APPLICATION = 101,
        POWER = 102,
        KP_EQUALS = 103,
        F13 = 104,
        F14 = 105,
        F15 = 106,
        F16 = 107,
        F17 = 108,
        F18 = 109,
        F19 = 110,
        F20 = 111,
        F21 = 112,
        F22 = 113,
        F23 = 114,
        F24 = 115,
        EXECUTE = 116,
        HELP = 117,
        MENU = 118,
        SELECT = 119,
        STOP = 120,
        AGAIN = 121,
        UNDO = 122,
        CUT = 123,
        COPY = 124,
        PASTE = 125,
        FIND = 126,
        MUTE = 127,
        VOLUMEUP = 128,
        VOLUMEDOWN = 129,

        KP_COMMA = 133,
        KP_EQUALSAS400 = 134,

        INTERNATIONAL1 = 135,
        INTERNATIONAL2 = 136,
        INTERNATIONAL3 = 137,
        INTERNATIONAL4 = 138,
        INTERNATIONAL5 = 139,
        INTERNATIONAL6 = 140,
        INTERNATIONAL7 = 141,
        INTERNATIONAL8 = 142,
        INTERNATIONAL9 = 143,
        LANG1 = 144,
        LANG2 = 145,
        LANG3 = 146,
        LANG4 = 147,
        LANG5 = 148,
        LANG6 = 149,
        LANG7 = 150,
        LANG8 = 151,
        LANG9 = 152,

        ALTERASE = 153,
        SYSREQ = 154,
        CANCEL = 155,
        CLEAR = 156,
        PRIOR = 157,
        RETURN2 = 158,
        SEPARATOR = 159,
        OPER = 161,
        CLEARAGAIN = 162,
        CRSEL = 163,
        EXSEL = 164,

        KP_00 = 176,
        KP_000 = 177,
        THOUSANDSSEPARATOR = 178,
        DECIMALSEPARATOR = 179,
        CURRENCYUNIT = 180,
        CURRENCYSUBUNIT = 181,
        KP_LEFTPAREN = 182,
        KP_RIGHTPAREN = 183,
        KP_LEFTBRACE = 184,
        KP_RIGHTBRACE = 185,
        KP_TAB = 186,
        KP_BACKSPACE = 187,
        KP_A = 188,
        KP_B = 189,
        KP_C = 190,
        KP_D = 191,
        KP_E = 192,
        KP_F = 193,
        KP_XOR = 194,
        KP_POWER = 195,
        KP_PERCENT = 196,
        KP_LESS = 197,
        KP_GREATER = 198,
        KP_AMPERSAND = 199,
        KP_DBLAMPERSAND = 200,
        KP_VERTICALBAR = 201,
        KP_DBLVERTICALBAR = 202,
        KP_COLON = 203,
        KP_HASH = 204,
        KP_SPACE = 205,
        KP_AT = 206,
        KP_EXCLAM = 207,
        KP_MEMSTORE = 208,
        KP_MEMRECALL = 209,
        KP_MEMCLEAR = 210,
        KP_MEMADD = 211,
        KP_MEMSUBTRACT = 212,
        KP_MEMMULTIPLY = 213,
        KP_MEMDIVIDE = 214,
        KP_PLUSMINUS = 215,
        KP_CLEAR = 216,
        KP_CLEARENTRY = 217,
        KP_BINARY = 218,
        KP_OCTAL = 219,
        KP_DECIMAL = 220,
        KP_HEXADECIMAL = 221,

        LCTRL = 224,
        LSHIFT = 225,
        LALT = 226,
        LGUI = 227,
        RCTRL = 228,
        RSHIFT = 229,
        RALT = 230,
        RGUI = 231,
    };
} // namespace ia::iae