#include "WindowSdl3.hpp"
#include "utils/Time.hpp"
#include "TimeInterfaceSdl3.hpp"
#include "Debug.hpp"
#include "extern/imgui_impl_sdl3.h"
#include "Sdl3Poller.hpp"

TSE::SDL3::WindowSdl3::WindowSdl3(string _title, int _width, int _height, IRenderingBackend *backend)
: WindowSdl3(_title, _width, _height, backend, WindowType::Windowed, 32){ }

TSE::SDL3::WindowSdl3::WindowSdl3(string _title, int _width, int _height, IRenderingBackend *backend, TSE::WindowType type)
: WindowSdl3(_title, _width, _height, backend, type, 32){ }

TSE::SDL3::WindowSdl3::WindowSdl3(string _title, int _width, int _height, IRenderingBackend *backend, TSE::WindowType type, int ppu)
{
    width = _width;
    height = _height;
    title = _title;
    windowType = type;
    renderingBackend = backend;
    renderingBackend->window = this;
    IWindow::lastWindow = this;
    if(!Init())
    {
        SDL_Quit();
        running = false;
    }
}

TSE::SDL3::WindowSdl3::~WindowSdl3()
{
    SDL_GL_DestroyContext(context);
    SDL_DestroyWindow(window);
    SDL_Quit();
}

bool TSE::SDL3::WindowSdl3::Init()
{
    if(!BaseInit() || !SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
    {
        Debug::Log("SDL3 Error");
        return false;
    }

    TSE::SDL3::Sdl3Poller::Init();
    Time::Init(new TimeInterfaceSdl3());

    renderingBackend->InitPreWindow();
    
    SDL_WindowFlags flags = SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_RESIZABLE;

    window = NULL;

    if(windowType == WindowType::Maximized)
    {
        window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_MAXIMIZED | flags);
    }
    else if(windowType == WindowType::Fullscreen)
    {
        window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | flags);
    }
    else if(windowType == WindowType::FullscreenWindowed)
    {
        window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS | flags);
    }
    else
    {
        window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | flags);
    }

    if(!window)
    {
        Debug::Log("Failed to create window. Maybe try another WindowType.");
        return false;
    }

    if(!renderingBackend->InitPostWindow())
    {
        return false;
    }

    Debug::Log("SDL:" + std::to_string(SDL_VERSION));

    if(!renderingBackend->InitEnd())
    {
        return false;
    }

    return true;
}

void TSE::SDL3::WindowSdl3::ResizeWindow(int w, int h)
{
    width = w;
    height = h;
    
    renderingBackend->onResize(width, height);

    for (auto const& i : objectsToResize)
    {
        i->OnResize(width, height, this);
    }
}

void TSE::SDL3::WindowSdl3::Clear() const
{
    renderingBackend->onClear();
}

void TSE::SDL3::WindowSdl3::Update()
{
    BaseUpdate();
    PollEvents();

    renderingBackend->onUpdate();
}

void TSE::SDL3::WindowSdl3::ClearDepthBuffer() const
{
    renderingBackend->onClearDepthBuffer();
}

bool TSE::SDL3::WindowSdl3::ShouldClose() const
{
    return !running;
}

void TSE::SDL3::WindowSdl3::DoneSetup()
{
    renderingBackend->onResize(width, height);

    for (auto const& i : objectsToResize)
    {
        i->OnResize(width, height, this);
    }
}

void TSE::SDL3::WindowSdl3::PollEvents()
{
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        if(useImGui)
        {
            ImGui_ImplSDL3_ProcessEvent(&event);
        }
        TSE::SDL3::Sdl3Poller::PollEvent(event);
        switch (event.type)
        {
        case SDL_EVENT_QUIT:
            running = false;
            break;
        case SDL_EVENT_WINDOW_RESIZED:
            ResizeWindow(event.window.data1, event.window.data2);
            break;
        case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
            ResizeWindow(event.window.data1, event.window.data2);
            break;
        default:
            break;
        }
    }
}
