#include "collision_map.hpp"

#include <algorithm>  // Para std::ranges::fill
#include <utility>    // Para std::move

CollisionMap::CollisionMap(std::vector<int> collision_tile_map)
    : collision_tile_map_(std::move(collision_tile_map)),
      extended_tile_map_(static_cast<size_t>(EW) * static_cast<size_t>(EH), 0),
      tile_collider_(extended_tile_map_, EW, EH, CollisionBorder::PX) {
    buildExtendedCenter();
}

// Copia los tiles de la room actual al centro del mapa extendido
void CollisionMap::buildExtendedCenter() {
    std::ranges::fill(extended_tile_map_, 0);

    for (int row = 0; row < MH; ++row) {
        for (int col = 0; col < MW; ++col) {
            extended_tile_map_[((row + B) * EW) + (col + B)] =
                collision_tile_map_[(row * MW) + col];
        }
    }
}

// Copia una región rectangular de src (MW×MH) al mapa extendido
void CollisionMap::copyRegion(const std::vector<int>& src,
    int src_col,
    int src_row,
    int dst_col,
    int dst_row,
    int cols,
    int rows) {
    for (int r = 0; r < rows; ++r) {
        for (int c = 0; c < cols; ++c) {
            extended_tile_map_[((dst_row + r) * EW) + (dst_col + c)] =
                src[((src_row + r) * MW) + (src_col + c)];
        }
    }
}

// Rellena los bordes del mapa extendido con tiles de las habitaciones adyacentes
void CollisionMap::updateBorders(const AdjacentData& adj) {
    // Reconstruir: limpiar bordes y copiar centro
    buildExtendedCenter();

    // Cardinales
    // TOP: últimas B filas de la room de arriba → filas 0..B-1 del extendido
    if (adj.top != nullptr) {
        copyRegion(*adj.top, 0, MH - B, B, 0, MW, B);
    }
    // BOTTOM: primeras B filas de la room de abajo → filas B+MH..B+MH+B-1
    if (adj.bottom != nullptr) {
        copyRegion(*adj.bottom, 0, 0, B, B + MH, MW, B);
    }
    // LEFT: últimas B columnas de la room izquierda → cols 0..B-1
    if (adj.left != nullptr) {
        copyRegion(*adj.left, MW - B, 0, 0, B, B, MH);
    }
    // RIGHT: primeras B columnas de la room derecha → cols B+MW..B+MW+B-1
    if (adj.right != nullptr) {
        copyRegion(*adj.right, 0, 0, B + MW, B, B, MH);
    }

    // Diagonales (esquinas B×B)
    // TOP-LEFT: esquina inferior-derecha de la room diagonal
    if (adj.top_left != nullptr) {
        copyRegion(*adj.top_left, MW - B, MH - B, 0, 0, B, B);
    }
    // TOP-RIGHT: esquina inferior-izquierda de la room diagonal
    if (adj.top_right != nullptr) {
        copyRegion(*adj.top_right, 0, MH - B, B + MW, 0, B, B);
    }
    // BOTTOM-LEFT: esquina superior-derecha de la room diagonal
    if (adj.bottom_left != nullptr) {
        copyRegion(*adj.bottom_left, MW - B, 0, 0, B + MH, B, B);
    }
    // BOTTOM-RIGHT: esquina superior-izquierda de la room diagonal
    if (adj.bottom_right != nullptr) {
        copyRegion(*adj.bottom_right, 0, 0, B + MW, B + MH, B, B);
    }
}

void CollisionMap::setCollisionTile(int index, int value) {
    if (index >= 0 && index < static_cast<int>(collision_tile_map_.size())) {
        collision_tile_map_[index] = value;
        // Actualizar también el tile correspondiente en el mapa extendido
        int row = index / MW;
        int col = index % MW;
        extended_tile_map_[((row + B) * EW) + (col + B)] = value;
    }
}
