#pragma once

#include <cstdint>
#include <vector>

#include "utils/defines.hpp"

class TileCollider {
   public:
    enum class Tile : std::uint8_t {
        EMPTY = 0,
        WALL = 1,
        PASSABLE = 2,
        SLOPE_L = 3,
        SLOPE_R = 4,
        KILL = 5
    };

    struct FloorHit {
        float y{-1};
        Tile type{Tile::EMPTY};
        int tile_x{0};
        int tile_y{0};
    };

    struct SlopeInfo {
        bool on_slope{false};
        Tile type{Tile::EMPTY};
        int tile_x{0};
        int tile_y{0};
        float surface_y{0};
    };

    // Constructor: recibe el tilemap extendido y sus dimensiones.
    // border_px es el offset en píxeles para traducir coordenadas de room-space a extended-map.
    TileCollider(const std::vector<int>& extended_tile_map, int width, int height, int border_px);

    // Queries básicas
    [[nodiscard]] auto getTileAt(int tile_x, int tile_y) const -> Tile;
    [[nodiscard]] auto isSolid(int tile_x, int tile_y) const -> bool;
    [[nodiscard]] auto getSlopeY(int tile_x, int tile_y, float px) const -> float;

    // Colisión para el Player
    [[nodiscard]] auto checkWallLeft(float x, float y, float w, float h) const -> float;
    [[nodiscard]] auto checkWallRight(float x, float y, float w, float h) const -> float;
    [[nodiscard]] auto checkCeiling(float x, float y, float w) const -> float;
    [[nodiscard]] auto checkFloor(float x, float foot_y_current, float w, float foot_y_new) const -> FloorHit;
    [[nodiscard]] auto hasGroundBelow(float x, float foot_y, float w) const -> bool;
    [[nodiscard]] auto checkSlopeBelow(float x, float foot_y, float w) const -> SlopeInfo;

    // Devuelve true si el jugador está parcialmente dentro de algún tile de slope
    [[nodiscard]] auto isInsideAnySlope(float x, float foot_y, float w) const -> bool;

    // Devuelve true si el rectángulo del jugador solapa algún tile KILL
    [[nodiscard]] auto touchesKillTile(float x, float y, float w, float h) const -> bool;

    // Convierte píxeles en room-space a índice de tile en el mapa extendido.
    [[nodiscard]] auto toTile(int px) const -> int { return (px + border_px_) / TS; }

    // Convierte índice de tile del mapa extendido a píxeles en room-space.
    [[nodiscard]] auto toPixel(int tile) const -> float {
        return static_cast<float>((tile * TS) - border_px_);
    }

   private:
    static constexpr int TS = ::Tile::SIZE;

    int width_;      // Ancho total del tilemap extendido (en tiles)
    int height_;     // Alto total del tilemap extendido (en tiles)
    int border_px_;  // Offset en píxeles (CollisionBorder::PX)

    const std::vector<int>& tile_map_;

    // Calcula la y del suelo per a un tile concret (helper de checkFloor)
    [[nodiscard]] auto floorYForTile(Tile tile, int col, int row, float x, float w, float foot_y_current, float foot_y_new) const -> float;
};
