//
// Created by m on 12/3/21.
//

#include "visualizer.hpp"
#include "tilemap.hpp"

bool Visualizer::update(InputResult input) {
    if(input.keycode == KEY_ESCAPE) {
        return true;
    }
    switch(input.keycode) {
        case KEY_RIGHT: x += 1; break;
        case KEY_LEFT: x -= 1; break;
        case KEY_UP: y -= 1; break;
        case KEY_DOWN: y += 1; break;
        default: break;
    }

    this->x = std::clamp(this->x, 0, (int)this->tile_map.get_width()-1);
    this->y = std::clamp(this->y, 0, (int)this->tile_map.get_height()-1);
    this->camera.move_camera(Point{x,y});


    return false;
}

void Visualizer::render(Renderer *renderer) {
    SpriteSheet tiles = SpriteSheet{"sprites/map1.bmp", tile_width, tile_height};
    SpriteSheet characters = SpriteSheet{"sprites/character.bmp", tile_width, tile_height, COLOR_BLACK};
    auto grass = Sprite{&tiles, 0};
    auto wall = Sprite{&tiles, 497};
    auto character = Sprite{&characters, this->sprite_index};
    auto bounds = this->camera.get_bounds();
    for(Point p : camera.get_range()) {
        auto wp = camera.camera_coords_to_screen_coords(p);
        int wx = wp.x, wy = wp.y;
        if(this->tile_map.get_tile(p.x, p.y) == floor_char) {
            renderer->draw_sprite(grass, wx*tile_width, wy*tile_height);
        }
        else {
            renderer->draw_sprite(wall, wx*tile_width, wy*tile_height);
        }
        if(p.x == x && p.y == y) {
            renderer->draw_sprite(character, wx*tile_width, wy*tile_height);
        }
    }
}

void Visualizer::initialize(GameInitArgs args) {
    this->window_width = args.window_width;
    this->window_height = args.window_height;
    Engine::load_config(CONFIG_FILE, [this](toml::table table) {
        this->tile_width = table["rendering"]["tile_size_w"].value_or(DEFAULT_TILE_WIDTH);
        this->tile_height = table["rendering"]["tile_size_h"].value_or(DEFAULT_TILE_HEIGHT);
        this->map_size_w = table["map"]["map_size_w"].value_or(DEFAULT_MAP_SIZE_W);
        this->map_size_h = table["map"]["map_size_h"].value_or(DEFAULT_MAP_SIZE_H);
        this->floor_char = table["map"]["floor_char"].value_or(DEFAULT_FLOOR_CHAR)[0];
        this->wall_char = table["map"]["wall_char"].value_or(DEFAULT_WALL_CHAR)[0];
    });
    int tilesx = (window_width / tile_width)+1;
    int tilesy = (window_height / tile_height)+1;
    initialize_map(map_size_w, map_size_h);
    this->camera = Camera(Point{x,y}, tilesx, tilesy, tile_map.get_width(), tile_map.get_height());
    this->algorithm_manager = AlgorithmManager(args.target_fps);
    this->initialize_context();



}

void Visualizer::initialize_map(int width, int height) {
    this->tile_map = TileMap(width, height, wall_char, floor_char);
    for(int ty=0;ty<this->tile_map.get_height();ty++) {
        for (int tx = 0; tx < tile_map.get_width(); tx++) {
            this->tile_map.draw_floor(tx, ty);
        }
    }
}

void Visualizer::initialize_context() {
    auto lua = lua_context_manager.get_default_context();

    auto tilemap_lua = lua->new_usertype<TileMap>("TileMap", sol::no_constructor);
    tilemap_lua["draw_floor"] = &TileMap::draw_floor;
    tilemap_lua["draw_wall"] = &TileMap::draw_wall;
    tilemap_lua["fill"] = &TileMap::fill;
    tilemap_lua["is_wall"] = &TileMap::is_wall;

    auto algo_manager_lua = lua->new_usertype<AlgorithmManager>("AlgorithmManager", sol::no_constructor);
    algo_manager_lua["register_algorithm"] = &AlgorithmManager::register_algorithm;
}

Visualizer::~Visualizer() = default;
