#pragma once
#include <string>
#include "imgui.h"
#include "GLFW/glfw3.h"
#include <vulkan/vulkan.hpp>

class renderer;
class pixel_shader_drawer;
class render_target;
class texture;
class application;

extern bool g_is_running;
extern bool g_exit_requested;
extern application* g_app_instance;

struct window_params {
    std::string title;
    int width;
    int height;
    bool fullscreen;
    bool borderless;
    bool resizable;
    bool minimized;
    bool maximized;
    bool hi_dpi;
    bool always_on_top;
};

class CORE_API application {
public:
    application() {
        g_app_instance = this;
    }

    virtual ~application() = default;

    application(const application&) = delete;

    application(application&&) = delete;

    static application* get() {
        return g_app_instance;
    }

    virtual void init(const window_params& in_window_params, int argc, char** argv);

    virtual int run();

    virtual void shutdown();

    virtual void draw_gui() = 0;

    virtual const char* get_shader_path() = 0;

    virtual void init_imgui(ImGuiContext* in_context) = 0;

    [[nodiscard]] std::shared_ptr<texture> load_texture(const std::string& path, vk::Format format = vk::Format::eR8G8B8A8Unorm) const;

    std::shared_ptr<texture> create_texture(const unsigned char* data, int width, int height, vk::Format format) const;

    [[nodiscard]] std::shared_ptr<render_target> create_render_target(int width, int height,
                                                                      vk::Format format) const;

    [[nodiscard]] std::shared_ptr<pixel_shader_drawer> create_pixel_shader_drawer() const;

    [[nodiscard]] virtual const char* get_entry_model() const = 0;

    [[nodiscard]] virtual const char* get_draw_ps_vertex_shader_entry() const = 0; // Vertex Shader used for drawing ps

    [[nodiscard]] renderer* get_renderer() const { return renderer_; }
    [[nodiscard]] GLFWwindow* get_window() const { return window_; }

protected:
    renderer* renderer_ = nullptr;
    GLFWwindow* window_ = nullptr;
    std::shared_ptr<spdlog::logger> async_spdlog_;

private:
    static void init_glfw();

    void init_imgui();

    void destroy_glfw();

    void destroy_imgui();
};