#pragma once

#include <deque>
#include <vector>

#include "Building.h"
#include "GameConfig.h"
#include "BuildingGrid.h"
#include "BuildingId.h"
#include "ItemType.h"
#include "Tick.h"

// One pending demolition of a fully-built building (REQ-BLD-DECON-QUEUE).
// completesAt == 0 means "queued but its timer has not started yet"
// (mirrors ConstructionSite). For a Splitter, the filters it had are captured
// here so cancelDeconstruction can restore them on re-registration.
struct DeconstructionEntry
{
    BuildingId            id          = kInvalidBuildingId;
    Tick                  completesAt = 0;
    std::vector<ItemType> splitterFilterA;
    std::vector<ItemType> splitterFilterB;
};

// The factory's world data: every building, the work queued on them, and the
// tile ownership index. This is the buildings-side counterpart to EntityAdmin —
// data with no behaviour of its own beyond what BuildingGrid encapsulates.
//
// Buildings deliberately stay a plain vector rather than becoming EnTT entities
// (see docs/architecture.md). Separating this data from the systems that operate
// on it is not a step toward putting them in the entity model; it is the same
// data/behaviour split the ecs/system/ classes already follow, where world data
// arrives as a tick argument instead of being owned by the system.
//
// Owned by Simulation (and by ArenaSimulation in the balancing tool), not by the
// systems that operate on it. BuildingSystem holds a reference. The remaining step
// is to pass this into the tick methods instead, so the systems become stateless
// over it — that one is gated on the query surface, which today reaches the data
// through BuildingSystem's ~180 const call sites.
struct FactoryState
{
    std::vector<Building>           buildings;
    std::deque<ConstructionSite>    constructionQueue;
    std::deque<DeconstructionEntry> deconstructionQueue;

    // The authority on which building owns which tile; every placement and removal
    // path claims and releases its body cells here.
    BuildingGrid                    grid;

    // Current buildable asteroid width, the left bound for placement. Grows as the
    // player buys expansions (REQ-EXP-UNLOCK). Deliberately not checksummed: it is
    // derived from config and Simulation's expansion count, which is folded already.
    // Seeded from config by BuildingSystem's constructor.
    int                             asteroidWidth_tiles = 0;
};

// A fresh factory for a new run: nothing built, and the asteroid bound seeded from
// config. Every owner of a FactoryState creates it this way — the bound has no
// sensible default without the config, so a default-constructed state would refuse
// every placement on the asteroid.
inline FactoryState makeFactoryState(const GameConfig& config)
{
    FactoryState state;
    state.asteroidWidth_tiles = config.world.regions.asteroidWidth_tiles;
    return state;
}
