#pragma once

#include <sstream>  // Para ostringstream
#include <string>   // Para string
#include <vector>   // Para vector

#include "external/fkyaml_node.hpp"           // Para fkyaml::node
#include "game/entities/door.hpp"             // Para Door::Data
#include "game/entities/enemy.hpp"            // Para Enemy::Data
#include "game/entities/item.hpp"             // Para Item::Data
#include "game/entities/key.hpp"              // Para Key::Data
#include "game/entities/moving_platform.hpp"  // Para MovingPlatform::Data
#include "game/gameplay/room.hpp"             // Para Room::Data

/**
 * @brief Autoridad única del formato yaml de habitaciones
 *
 * Esta clase es el ÚNICO sitio del código que conoce la estructura del
 * fichero room.yaml. Combina parser (loadYAML) y serializador (saveYAML, en
 * builds de debug) en un mismo módulo para forzar que cuando se añada un
 * campo nuevo se actualicen ambos lados al mismo tiempo.
 *
 * Reemplaza al antiguo `RoomLoader` y `RoomSaver`. La versión nueva:
 *  - Elimina la rama de retrocompatibilidad para tilemaps con formato antiguo
 *    (un yaml sin `tilemap.draw`/`tilemap.collision` ahora da error claro,
 *    no un crash diferido por collision_tile_map vacío).
 *  - Simplifica saveYAML para no recibir el yaml original (ya no se usaba).
 *  - Añade createDefault() para que MapEditor::createNewRoom no tenga que
 *    conocer el formato.
 */
class RoomFormat {
   public:
    RoomFormat() = delete;
    ~RoomFormat() = delete;
    RoomFormat(const RoomFormat&) = delete;
    auto operator=(const RoomFormat&) -> RoomFormat& = delete;
    RoomFormat(RoomFormat&&) = delete;
    auto operator=(RoomFormat&&) -> RoomFormat& = delete;

    /**
     * @brief Carga un room.yaml desde disco/pack y devuelve Room::Data
     *
     * Usa Resource::Helper::loadFile, que soporta tanto el resource pack
     * como el filesystem. Disponible en runtime (lo usa Resource::Cache).
     */
    static auto loadYAML(const std::string& file_path, bool verbose = false) -> Room::Data;

#ifdef _DEBUG
    /**
     * @brief Carga un room desde un string yaml (usado por reloadRoom del cache)
     */
    static auto loadFromString(const std::string& yaml_content, const std::string& file_name) -> Room::Data;

    /**
     * @brief Serializa Room::Data al disco. Solo el editor escribe rooms.
     * @return mensaje de éxito o error (prefijo "Error" si falla)
     */
    static auto saveYAML(const std::string& file_path, const Room::Data& data) -> std::string;

    /**
     * @brief Construye un Room::Data válido y completo con valores por defecto
     *
     * Lo usa MapEditor::createNewRoom para no tener que conocer el formato.
     * El campo `number` y las conexiones recíprocas los rellena el caller.
     */
    static auto createDefault() -> Room::Data;
#endif

   private:
    // --- Parsing helpers (siempre disponibles, los usa loadYAML) ---
    static auto convertRoomConnection(const std::string& value) -> std::string;
    static auto convertAutoSurface(const fkyaml::node& node) -> int;
    static auto flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int>;
    static void parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name);
    static void parseRoomConnections(const fkyaml::node& conn_node, Room::Data& room);
    static void parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose);
    static void parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool verbose);
    static auto parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data;
    static void parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Data& enemy);
    static void parseItems(const fkyaml::node& yaml, Room::Data& room, bool verbose);
    static auto parseItemData(const fkyaml::node& item_node) -> Item::Data;
    static void parsePlatforms(const fkyaml::node& yaml, Room::Data& room, bool verbose);
    static auto parsePlatformData(const fkyaml::node& platform_node) -> MovingPlatform::Data;
    static void parseKeys(const fkyaml::node& yaml, Room::Data& room, bool verbose);
    static auto parseKeyData(const fkyaml::node& key_node) -> Key::Data;
    static void parseDoors(const fkyaml::node& yaml, Room::Data& room, bool verbose);
    static auto parseDoorData(const fkyaml::node& door_node) -> Door::Data;
    static void parseAll(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose);

#ifdef _DEBUG
    // --- Serialization helpers (solo en debug, los usa saveYAML) ---
    static auto buildContent(const Room::Data& room_data) -> std::string;
    static auto roomConnectionToYAML(const std::string& connection) -> std::string;
    static void writeRoomSection(std::ostringstream& out, const Room::Data& room_data);
    static void writeTilemapSection(std::ostringstream& out, const Room::Data& room_data);
    static void writeEnemiesSection(std::ostringstream& out, const Room::Data& room_data);
    static void writeItemsSection(std::ostringstream& out, const Room::Data& room_data);
    static void writePlatformsSection(std::ostringstream& out, const Room::Data& room_data);
    static void writeKeysSection(std::ostringstream& out, const Room::Data& room_data);
    static void writeDoorsSection(std::ostringstream& out, const Room::Data& room_data);
#endif
};
