#include "PlacementRules.h"

#include "BuildingType.h"
#include "FactoryQueries.h"
#include "SurfaceMask.h"

bool bodyCellsWithinWorldBounds(const FactoryState& state, const GameConfig& config,const std::vector<QPoint>& bodyCells,
                                                QPoint anchor)
{
    const int heightTiles = config.world.heightTiles;
    const int leftEdgeX   = -state.asteroidWidth_tiles;
    for (const QPoint& cell : bodyCells)
    {
        const QPoint worldCell = anchor + cell;
        if (worldCell.y() < 0 || worldCell.y() >= heightTiles)
        {
            return false;
        }
        if (worldCell.x() < leftEdgeX)
        {
            return false;
        }
    }
    return true;
}

bool isPlacementValid(const FactoryState& state, const GameConfig& config,BuildingType type, QPoint anchor,
                                      Rotation rotation)
{
    const BuildingDef* def = config.buildings.findBuildingDef(type);
    if (def == nullptr)
    {
        return false;
    }
    const ParsedSurfaceMask mask = parseSurfaceMask(def->surfaceMask, rotation);

    if (!bodyCellsWithinWorldBounds(state, config, mask.bodyCells, anchor))
    {
        return false;
    }

    // Terrain: ship-dock (S) cells must sit in space (x >= 0); all other body
    // (A) cells must sit on the asteroid (x < 0). (REQ-BLD-PLACE-VALID)
    for (const QPoint& cell : mask.bodyCells)
    {
        const QPoint worldCell = anchor + cell;
        bool isShipDock = false;
        for (const QPoint& dock : mask.shipDockCells)
        {
            if (dock == cell)
            {
                isShipDock = true;
                break;
            }
        }
        if (isShipDock)
        {
            if (worldCell.x() < 0)
            {
                return false;
            }
        }
        else if (worldCell.x() >= 0)
        {
            return false;
        }
    }
    return true;
}


std::optional<BuildingId> findRotateInPlaceTarget(const FactoryState& state, const GameConfig& config,
    BuildingType type, QPoint anchor, Rotation rot)
{
    // Tunnel Entries and Tunnel Exits cannot be rotated in place; re-orienting a
    // tunnel requires deconstructing and re-placing it (REQ-BLD-ROTATE-IN-PLACE).
    if (type == BuildingType::TunnelEntry || type == BuildingType::TunnelExit)
    {
        return std::nullopt;
    }

    const BuildingDef* def = config.buildings.findBuildingDef(type);
    if (!def) { return std::nullopt; }

    const ParsedSurfaceMask mask = parseSurfaceMask(def->surfaceMask, rot);
    if (mask.bodyCells.empty()) { return std::nullopt; }

    // All body cells must be occupied by the same entity.
    const QPoint firstAbs = anchor + mask.bodyCells[0];
    const std::optional<BuildingId> firstOwner = state.grid.findOwner(firstAbs);
    if (!firstOwner.has_value()) { return std::nullopt; }
    const BuildingId candidateId = *firstOwner;

    for (const QPoint& rel : mask.bodyCells)
    {
        const std::optional<BuildingId> owner = state.grid.findOwner(anchor + rel);
        if (!owner.has_value() || *owner != candidateId)
        {
            return std::nullopt;
        }
    }

    // Verify the candidate is the same building type with the same cell count.
    for (const ConstructionSite& site : state.constructionQueue)
    {
        if (site.id != candidateId) { continue; }
        if (site.type != type) { return std::nullopt; }
        if (site.bodyCells.size() != mask.bodyCells.size()) { return std::nullopt; }
        return candidateId;
    }
    for (const Building& b : state.buildings)
    {
        if (b.id != candidateId) { continue; }
        if (b.type != type) { return std::nullopt; }
        if (b.bodyCells.size() != mask.bodyCells.size()) { return std::nullopt; }
        return candidateId;
    }

    return std::nullopt;
}

