#include "buildings.h"

#include "components.h"
#include "entity_factory.h"
#include "game_state.h"
#include "map_layers.h"
#include "systems/systems.h"

#include <raymath.h>

bool canPlaceBuilding(Game *game, BuildingType type, BzTile tileX, BzTile tileY) {
    i32 sizeX, sizeY;
    getBuildingSize(type, &sizeX, &sizeY);
    if (sizeX == 0 || sizeY == 0) return false;

    BzTileMap *map = &game->map;
    // Ensure that it is within the map
    if (tileX < 0 || tileX + sizeX > map->width ||
        tileY < 0 || tileY + sizeY > map->height)
        return false;

    Rectangle buildArea = {tileX * map->tileWidth, tileY * map->tileHeight,
                           sizeX * map->tileWidth, sizeY * map->tileHeight};

    BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, buildArea.x, buildArea.y, buildArea.width, buildArea.height);
    while (bzSpatialGridQueryNext(&it)) {  ecs_entity_t entity = *(ecs_entity_t *) it.data;
        Rectangle bounds;
        if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue;

        if (CheckCollisionRecs(buildArea, bounds))
            return false;
    }
    return true;
}

ecs_entity_t placeBuilding(Game *game, BuildingType type,
                           BzTile posX, BzTile posY, Owner owner) {
    if (type <= BUILDING_NONE || type >= BUILDING_COUNT)
        return 0;
    i32 sizeX, sizeY;
    getBuildingSize(type, &sizeX, &sizeY);

    const i32 tileWidth  = game->map.tileWidth;
    const i32 tileHeight = game->map.tileHeight;

    // Create entity
    ecs_entity_t building = entityCreateEmpty();
    ecs_add_id(ECS, building, Selectable);
    ecs_set(ECS, building, Building, {
        .type = type,
        .pos = (Vec2i) { posX, posY },
        .size = (Vec2i) { sizeX, sizeY }
    });
    Position pos = {
            .x = posX * tileWidth + sizeX * tileWidth * 0.5f,
            .y = posY * tileHeight + sizeY * tileHeight * 0.5f
    };
    Size size = {
            .x = sizeX * tileWidth,
            .y = sizeY * tileHeight
    };

    ecs_set_ptr(ECS, building, Position, &pos);
    ecs_set_ptr(ECS, building, Size, &size);
    ecs_set(ECS, building, Rotation, {0});

    SpatialGridID gridID = bzSpatialGridInsert(game->entityGrid, &building,
                                               pos.x - size.x * 0.5f, pos.y - size.y * 0.5f,
                                               size.x, size.y);
    ecs_set_ptr(ECS, building, SpatialGridID, &gridID);
    ecs_set_ptr(ECS, building, Owner, &owner);
    BzTileset *tileset = &game->tileset;
    TextureRegion region = {
            tileset->tiles,
            bzTilesetGetTileRegion(tileset, getBuildingTile(type))
    };
    region.rec.width *= sizeX;
    region.rec.height *= sizeY;
    ecs_set_ptr(ECS, building, TextureRegion, &region);

    bzTileMapSetCollisions(&game->map, true, posX, posY, sizeX, sizeY);

    switch (type) {
        case BUILDING_KEEP:
            ecs_add_id(ECS, building, Storage);
            break;
        default:
            break;
    }

    return building;

}

Vector2 getPositionNearBuilding(ecs_entity_t building, Vector2 fromPos) {
    BZ_ASSERT(ecs_is_alive(ECS, building));
    BZ_ASSERT(ecs_has(ECS, building, Position));
    BZ_ASSERT(ecs_has(ECS, building, Size));

    Vector2 pos  = *ecs_get(ECS, building, Position);
    Vector2 size = *ecs_get(ECS, building, Size);

    size = Vector2SubtractValue(size, 10.0f);

    Vector2 dir = Vector2Normalize(Vector2Subtract(fromPos, pos));
    dir         = Vector2Multiply(dir, size);

    pos = Vector2Add(pos, dir);
    return pos;
}
