#pragma once
/*
 * Created by Brett on 28/11/23.
 * Licensed under GNU General Public License V3.0
 * See LICENSE file for license detail
 */

#ifndef BLT_WITH_GRAPHICS_TEMPLATE_WINDOW_H
#define BLT_WITH_GRAPHICS_TEMPLATE_WINDOW_H

#include <blt/gfx/gl_includes.h>
#include <GLFW/glfw3.h>
#include <functional>
#include <cstdint>
#include <string>
#include <utility>

namespace blt::gfx
{
    struct window_context
    {
        std::int32_t GL_MAJOR = 4;
        std::int32_t GL_MINOR = 6;
        std::int32_t DOUBLE_BUFFER = GLFW_TRUE;
        std::int32_t GL_PROFILE = GLFW_OPENGL_CORE_PROFILE;
        std::int32_t SAMPLES = 8;
    };
    
    struct window_data
    {
        private:
            std::function<void(const window_data&)> init;
            std::function<void(const window_data&)> update;
        public:
            std::string title;
            std::int32_t width;
            std::int32_t height;
            
            window_context context{};
            std::int32_t sync_interval = 0;
            
            window_data(std::string title, std::function<void(const window_data&)> init, std::function<void(const window_data&)> update,
                        std::int32_t width = 640, std::int32_t height = 480): init(std::move(init)), update(std::move(update)),
                                                                              title(std::move(title)), width(width), height(height)
            {}
            
            inline void call_init() const
            {
                init(*this);
            }
            
            inline void call_update() const
            {
                update(*this);
            }
            
            window_data& setWindowSize(int32_t new_width, int32_t new_height);
            
            window_data& setHeight(int32_t new_height)
            {
                setWindowSize(width, new_height);
                return *this;
            }
            
            window_data& setWidth(int32_t new_width)
            {
                setWindowSize(new_width, height);
                return *this;
            }
            
            window_data& setTitle(const std::string& title_str)
            {
                window_data::title = title_str;
                return *this;
            }
            
            window_data& setContext(const window_context& ctx)
            {
                context = ctx;
                return *this;
            }
            
            window_data& setSyncInterval(std::int32_t sync)
            {
                sync_interval = sync;
                return *this;
            }
    };
    
    void init(window_data data);
    
    double getMouseX();
    
    double getMouseY();
    
    double getMouseDX();
    
    double getMouseDY();
    
    bool mouseMovedLastFrame();
    
    void lockCursor();
    
    void unlockCursor();
    
    bool isCursorLocked();
    
    bool isCursorInWindow();
    
    void setRawInput(bool state);
    
    bool isRawInput();
    
    void setClipboard(const std::string& str);
    
    std::string getClipboard();
    
    bool isMousePressed(int button);
    
    bool mousePressedLastFrame();
    
    bool isKeyPressed(int key);
    
    // TODO: maybe make this per key?
    bool keyPressedLastFrame();
    
    double getFrameDeltaSeconds();
    
    double getFrameDeltaMilliseconds();
    
    std::int64_t getFrameDelta();
    
    void cleanup();
    
    
}

#endif //BLT_WITH_GRAPHICS_TEMPLATE_WINDOW_H
