#include "Application.h"
#include "Event.h"
#include "Log.h"
#include "imgui.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_sdlrenderer2.h"
#include "imgui_impl_sdlrenderer3.h"

#if !SDL_VERSION_ATLEAST(2, 0, 17)
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
#endif

WindowData Application::m_WindowData;
bool Application::m_isRunning = false;

Application::Application() : m_Renderer(nullptr) {}

Application::~Application() { Shutdown(); }

bool Application::Init() {
    SetRunningState(true);

    SakuraVNE::Log::Init();
    LOG_INFO("Initialized logger library");

    LOG_INFO("window width: {0}, height: {1}", GetWindowData().width, GetWindowData().height);

    // Init sdl
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER /*| SDL_INIT_GAMECONTROLLER*/) < 0) {
        LOG_ERROR("SDL could not be initialized! {0}", SDL_GetError());
        Shutdown();
        return false;
    }

#ifdef SDL_HINT_IME_SHOW_UI
    SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif

    // TODO: add the resizable flag and update the window size with the event system
    SDL_WindowFlags windowFlags = (SDL_WindowFlags)(SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE);
    m_Window = SDL_CreateWindow(GetWindowData().title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, GetWindowData().width, GetWindowData().height, windowFlags);

    if (!m_Window) {
        LOG_ERROR("SDL window could not be created! {0}", SDL_GetError());
        Shutdown();

        return false;
    } else {
        LOG_INFO("SDl window created");
    }

    m_Renderer = SDL_CreateRenderer(m_Window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
    if (!m_Renderer) {
        LOG_ERROR("Renderer could not be created! {0}", SDL_GetError());
    } else {
        LOG_INFO("SDL renderer created");

        SDL_RendererInfo info;
        SDL_GetRendererInfo(m_Renderer, &info);
    }

    /*m_Surface = SDL_GetWindowSurface(m_Window);
    if (!m_Surface) {
        LOG_ERROR("SDL surface could not be created! {0}", SDL_GetError());
        Shutdown();

        return false;
    } else {
        LOG_INFO("SDl surface created");
    }*/

    // Imgui init
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();

    ImGuiIO &io = ImGui::GetIO();
    (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
    // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;

    ImGui::StyleColorsDark();

    ImGui_ImplSDL2_InitForSDLRenderer(m_Window, m_Renderer);
    ImGui_ImplSDLRenderer2_Init(m_Renderer);

    return true;
}

void Application::Run() {
    bool demoWindowShow = true;
    bool showOtherWindow = false;
    ImVec4 clearColor = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

    ImGuiIO &io = ImGui::GetIO();

    while (GetRunningState()) {
        SDL_Event event;

        while (SDL_PollEvent(&event)) {
            ImGui_ImplSDL2_ProcessEvent(&event);

            if (event.type == SDL_QUIT) {
                SetRunningState(false);
                LOG_INFO("Running state: {0}", GetRunningState());
            }

            if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(GetSDLWindow())) {
                SetRunningState(false);
            }

            if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
                SDL_GetWindowSize(GetSDLWindow(), &GetWindowData().width, &GetWindowData().height);

                SetSDLWindowSurface(SDL_GetWindowSurface(GetSDLWindow()));
            }
        }

        ImGui_ImplSDLRenderer2_NewFrame();
        ImGui_ImplSDL2_NewFrame();
        ImGui::NewFrame();

        if (demoWindowShow) {
            ImGui::ShowDemoWindow(&demoWindowShow);
        }

        // imgui demo window stuff or frame stuff
        static float f = 0.0f;
        static int counter = 0;

        ImGui::Begin("Hello World!"); // creates window and add later stuff to it

        ImGui::Text("text stuff");
        ImGui::Checkbox("Demo checkbox", &showOtherWindow);

        ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
        ImGui::ColorEdit3("clear color edit", (float *)&clearColor);

        if (ImGui::Button("Button"))
            counter++;

        ImGui::SameLine();
        ImGui::Text("counter = %d", counter);

        ImGui::Text("Application avg %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
        ImGui::End();

        // Rendering
        ImGui::Render();
        SDL_RenderSetScale(m_Renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
        SDL_SetRenderDrawColor(m_Renderer, (Uint8)(clearColor.x * 255), (Uint8)(clearColor.y * 255), (Uint8)(clearColor.z * 255), (Uint8)(clearColor.w * 255));
        SDL_RenderClear(m_Renderer);
        ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), m_Renderer);
        SDL_RenderPresent(m_Renderer);
    }
}

void Application::Shutdown() {
    LOG_WARN("Shutting down the application!");

    ImGui_ImplSDLRenderer2_Shutdown();
    ImGui_ImplSDL2_Shutdown();
    ImGui::DestroyContext();

    SDL_DestroyRenderer(m_Renderer);

    SDL_FreeSurface(m_Surface);

    // Destroy window
    SDL_DestroyWindow(m_Window);

    // Quit SDL subsystems
    SDL_Quit();
}
