#include <cute_tiled.h>
#include <stdio.h>

#include "tileset.h"
#include "../core/memory.h"

BzTileset BZ_TILESET_INVALID = {.isValid = false};

BzTileShape bzCuteObjectToTileShape(cute_tiled_object_t *object) {
    BzTileShape shape = {BZ_TILE_SHAPE_NONE};
    if (object->ellipse)
        shape.type = BZ_TILE_SHAPE_ELLIPSE;
    else if (object->point)
        shape.type = BZ_TILE_SHAPE_POINT;
    else if (!object->vertices)
        shape.type = BZ_TILE_SHAPE_RECT;
    else
        return shape;

    shape.x = object->x;
    shape.y = object->y;
    shape.sizeX = object->width;
    shape.sizeY = object->height;

    if (shape.type == BZ_TILE_SHAPE_ELLIPSE) {
        // Adjust to use radius and position to be center
        shape.sizeX *= 0.5f;
        shape.sizeY *= 0.5f;
        shape.x += shape.sizeX;
        shape.y += shape.sizeY;
    }

    return shape;
}

BzTileset bzTilesetCreate(const BzTilesetDesc *desc) {
    BzTileset tileset = {};
    cute_tiled_tileset_t *cuteTileset = cute_tiled_load_external_tileset(desc->path, NULL);

    tileset.tiles = LoadTexture(desc->texturePath);
    tileset.startID = cuteTileset->firstgid;
    tileset.tileWidth = cuteTileset->tilewidth;
    tileset.tileHeight = cuteTileset->tileheight;

    tileset.offsetX = cuteTileset->tileoffset_x;
    tileset.offsetY = cuteTileset->tileoffset_y;

    tileset.width = tileset.tiles.width / tileset.tileWidth;
    tileset.height = tileset.tiles.height / tileset.tileHeight;

    tileset.tileCount = tileset.width * tileset.tileHeight;
    tileset.tileColliders = bzAlloc(tileset.tileCount * sizeof(*tileset.tileColliders));
    for (i32 i = 0; i < tileset.tileCount; i++) {
        tileset.tileColliders[i] = (BzTileShape) {BZ_TILE_SHAPE_NONE};
    }

    cute_tiled_tile_descriptor_t *cuteTile = cuteTileset->tiles;
    for (; cuteTile; cuteTile = cuteTile->next) {
        if (!cuteTile->objectgroup) continue;
        cute_tiled_object_t *cuteObject = cuteTile->objectgroup->objects;
        // NOTE: Only supporting single collider (integer values)
        if (cuteObject) {

            BzTileShape collider = bzCuteObjectToTileShape(cuteObject);
            tileset.tileColliders[cuteTile->tile_index] = collider;
        }
    }


    if (tileset.tiles.width != cuteTileset->imagewidth ||
        tileset.tiles.height != cuteTileset->imageheight) {
        cute_tiled_free_external_tileset(cuteTileset);
        bzTilesetDestroy(&tileset);
        return BZ_TILESET_INVALID;
    }
    cute_tiled_free_external_tileset(cuteTileset);
    tileset.isValid = true;
    return tileset;
}

BzTile bzTilesetGetTile(BzTileset *tileset, BzTile tile) {
    if (tile == 0)
        return -1;
    tile = tile - tileset->startID;
    BZ_ASSERT(tile >= 0 && tile < tileset->tileCount);
    return tile;
}
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, BzTile tileID) {
    tileID = tileID - tileset->startID;
    if (tileID < 0 || tileID >= tileset->tileCount) {
        return (Rectangle){};
    }
    int posX = tileID % tileset->width;
    int posY = tileID / tileset->width;
    return (Rectangle) {posX * tileset->tileWidth, posY * tileset->tileHeight,
                        tileset->tileWidth, tileset->tileHeight};
}
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, BzTile tileID) {
    tileID = tileID - tileset->startID;

    if (tileID < 0 || tileID >= tileset->tileCount) {
        return (BzTileShape) {.type = BZ_TILE_SHAPE_NONE};
    }

    return tileset->tileColliders[tileID];
}

void bzTilesetDestroy(BzTileset *tileset) {
    UnloadTexture(tileset->tiles);
    bzFree(tileset->tileColliders);
    *tileset = BZ_TILESET_INVALID;
}

