#pragma once

#include <SDL3/SDL.h>

#include <memory>  // Para shared_ptr
#include <string>  // Para string
#include <vector>  // Para vector

#include "game/entities/door.hpp"  // Para Door, Door::Data

class SolidActorManager;

/**
 * @brief Gestor de puertas de una habitación
 *
 * Responsabilidades:
 * - Almacenar y gestionar la colección de puertas
 * - Actualizar y renderizar todas las puertas
 * - Detectar contacto del jugador con puertas cerradas y disparar la apertura
 *   si tiene la llave correspondiente (consultando el Inventory global)
 * - Registrar cada puerta en el SolidActorManager para que sus AABBs
 *   participen en los sweeps de colisión del Player. El bit BLOCKS_PLAYER
 *   del propio Door se encarga de activar/desactivar el bloqueo al abrir.
 * - Persistir el estado abierto en DoorTracker
 */
class DoorManager {
   public:
    DoorManager(std::string room_id, SolidActorManager* solid_actors);
    ~DoorManager() = default;

    // Prohibir copia y movimiento para evitar duplicación accidental
    DoorManager(const DoorManager&) = delete;
    auto operator=(const DoorManager&) -> DoorManager& = delete;
    DoorManager(DoorManager&&) = delete;
    auto operator=(DoorManager&&) -> DoorManager& = delete;

    // Gestión de puertas
    void addDoor(std::shared_ptr<Door> door);  // Añade una puerta y la registra en el SolidActorManager
    void clear();                              // Elimina todas las puertas

    // Actualización y renderizado
    void update(float delta_time);  // Actualiza animaciones y procesa transiciones a OPENED
    void render();                  // Renderiza todas las puertas

    // Estado
    void setPaused(bool paused);  // Pausa/despausa todas las puertas

    /**
     * @brief Intenta abrir las puertas cercanas al jugador si tiene la llave
     *
     * Infla el rectángulo del jugador en 1 px para detectar contacto
     * (las puertas cerradas son muros sólidos, así que el jugador queda
     * adyacente sin solapar). Para cada puerta CLOSED que solape el rect
     * inflado, si el Inventory contiene la llave correspondiente, llama a
     * door->startOpening().
     *
     * @param player_rect Rectángulo de colisión del jugador
     */
    void tryUnlock(const SDL_FRect& player_rect);

#ifdef _DEBUG
    // --- API para el editor (debug) ---
    [[nodiscard]] auto getCount() const -> int { return static_cast<int>(doors_.size()); }
    auto getDoor(int index) -> std::shared_ptr<Door>& { return doors_.at(index); }

    /**
     * @brief Mueve la puerta indicada a (x, y) en píxeles
     *
     * Reposiciona el sprite y el AABB de la puerta. El registro en el
     * SolidActorManager no cambia: el manager siempre lee el AABB actual
     * del SolidActor durante los sweeps.
     */
    void moveDoor(int index, float x, float y);

    /**
     * @brief Elimina la puerta indicada del vector y la desregistra del SolidActorManager
     */
    void removeDoor(int index);
#endif

   private:
    std::vector<std::shared_ptr<Door>> doors_;  // Colección de puertas
    std::string room_id_;                       // Identificador de la habitación
    SolidActorManager* solid_actors_;           // Referencia no propietaria al SolidActorManager de la Room
};
