/********************\
|  Copyright 2024,   |
|       Ulysse Cura  |
\********************/

/////////////////////////////////////
//                                 //
//   Definition de la classe Game. //
//                                 //
/////////////////////////////////////

#include <iostream> // cerr
#include <SDL2/SDL_image.h> // IMG_Init, IMG_GetError
#include <stdexcept> // runtime_error
#include "Camera.hpp" // Camera::
#include "ECS/Components.hpp" // ECS and Components definition
#include "Events.hpp" // Events::
#include "Game.hpp" // Game declaration
#include "IP/Properties.hpp" // Item definition
#include "MapManager.hpp" // MapManager::
#include "TextureManager.hpp" // TextureManager::
#include "TileMap.hpp" // TileMap::

using std::cerr, std::runtime_error;

SDL_Renderer *Game::renderer;
SDL_Texture *Game::textureRenderer;
Events Game::events;
TextureManager Game::textureManager;
Camera Game::camera {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
TileMap Game::tileMap;
MapManager Game::mapManager;
Manager Game::entityManager;

Entity &player(Game::entityManager.addEntity());

Game::~Game()
{
    if(renderer != NULL) SDL_DestroyRenderer(renderer);
    if(m_window != NULL) SDL_DestroyWindow(m_window);

    SDL_Quit();

    cerr << "Game cleaned.\n";
}

bool Game::Init()
{
    if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
    {
        cerr << "Erreur SDL_Init : " << SDL_GetError() << '\n';
        throw runtime_error("Impossible d'initialiser SDL2.\n");
    }
    cerr << "SDL initialised successfully.\n";

    if(IMG_Init(IMG_INIT_PNG) == 0)
    {
        cerr << "Erreur IMG_Init : " << IMG_GetError() << '\n';
        throw runtime_error("Impossible d'initialiser IMG.\n");
    }
    cerr << "IMG initialised successfully.\n";

    m_window = SDL_CreateWindow(WINDOW_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
    if(m_window == NULL)
    {
        cerr << "Erreur SDL_CreateWindow : " << SDL_GetError() << '\n';
        throw runtime_error("Impossible d'initialiser la fenêtre.\n");
    }
    cerr << "Window created successfully.\n";

    renderer = SDL_CreateRenderer(m_window, -1, 0);
    if(renderer == NULL)
    {
        cerr << "Erreur SDL_CreateRenderer : " << SDL_GetError() << '\n';
        throw runtime_error("Impossible d'initialiser le renderer.\n");
    }
    cerr << "Renderer created successfully\n\n";

    tileMap.LoadTileset("ressources/tileset/tileset.png");

    tileMap.LoadTileMap("ressources/maps/dungeon entry.json");

    TransformComponent *p_transform = &player.addComponent<TransformComponent>(tileMap.getPlayerInitPos(), Vector2D<int>(32, 32), 2, 3);
    player.addComponent<SpriteComponent>("ressources/heroes/knight/idle-sheet.png");
    player.addComponent<HitboxComponent>(Vector2D<float>(0.81f, 0.41f), Vector2D<float>(0.5f, 1.0f));
    InventoryComponent *p_inventory = &player.addComponent<InventoryComponent>();

    player.addComponent<AnimationSystem>();
    player.addComponent<PlayerSystem>();

    camera.camR.x = static_cast<int>(p_transform->position.x - static_cast<float>(camera.camR.w / 2 - p_transform->dimension.x * p_transform->scale / 2));
    camera.camR.y = static_cast<int>(p_transform->position.y - static_cast<float>(camera.camR.h / 2 - p_transform->dimension.y * p_transform->scale / 2));

    Item &item(p_inventory->addItem());

    item.addProperty<NameProperty>("Prout");

    m_isRunning = true;

    return true;
}

void Game::HandleEvents()
{
    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
        if(event.type == SDL_QUIT)
            m_isRunning = false;

        else if(event.type == SDL_KEYDOWN && event.key.repeat == 0)
            events.keys[event.key.keysym.scancode] = true;

        else if(event.type == SDL_KEYUP)
            events.keys[event.key.keysym.scancode] = false;
    }
}

void Game::Update()
{
    entityManager.refresh();

    entityManager.update();

    camera.update();
}

void Game::Render()
{
    // Dessin sur une texture intermediaire
    SDL_SetRenderTarget(renderer, textureRenderer);

    SDL_SetRenderDrawColor(renderer, 20, 20, 18, 255);
    SDL_RenderClear(renderer);

    tileMap.draw(1);
    tileMap.draw(2);

    entityManager.draw();

    tileMap.draw(3);

    // Affichage sur la fenêtre avec la caméra
    SDL_SetRenderTarget(renderer, NULL);

    SDL_RenderCopy(renderer, textureRenderer, &camera.camR, NULL);

    SDL_RenderPresent(renderer);
}

bool Game::Running()
{
    return m_isRunning;
}
