#pragma once

#include "../core/flags.hpp"
#include <tuple>

typedef struct GLFWwindow GLFWwindow;
typedef void (*GLFWframebuffersizefun)(GLFWwindow*, int, int);

/// GLFW context and window
class Window {
public:
    Window();
    ~Window();

    static constexpr auto MIN_FPS = 24;
    static constexpr auto MAX_FPS = 240;

    static constexpr auto RATIO_WIDTH = 16;
    static constexpr auto RATIO_HEIGHT = 9;
    /// Fixed window ratio
    static constexpr auto RATIO = RATIO_WIDTH / (RATIO_HEIGHT * 1.0f);

    struct CreateInfo {
        GLFWframebuffersizefun pfnResize;
        struct Client {
            enum class Type { GL, VK } type;
            int major;
            int minor;
        } client;
        int samples;
        int fps;
        bool fullscreen;
    };
    bool create(const CreateInfo &opt);
    void destroy();
    bool isReady() const;

    void setTargetFPS(int val);
    void setFullscreen(bool val);

    _FORCE_INLINE_ GLFWwindow *getPtr() { return ptr; }

    void startFrame();
    void waitTargetFPS();

    bool shouldClose();

    double getTime() const;

    static void wait(int microseconds = 100);

private:
    GLFWwindow *ptr;
    int targetFPS;
    bool fullscreen;
    double frameStart;
};

struct windowOptions {
#ifdef _WINDOWS
    //NOTE: prefer vsync due to clock inaccuracy
    int targetFPS = Window::MIN_FPS - 1;
#else
    int targetFPS = 60;
#endif
    int sampling = -1;
    bool fullscreen = false;

    constexpr int getSamples() const { return sampling > 0 ? (1 << (sampling - 1)) : sampling; }
};
