#pragma once

#include <map>
#include <optional>
#include <string>
#include <vector>

#include "Building.h"
#include "GameConfig.h"
#include "RecipesConfig.h"

// Production state of a building for the UI status light (REQ-UI-STATUS-LIGHT).
// The simulation owns the classification so it stays in sync with the
// production-cycle predicates (REQ-MAT-CYCLE); the UI maps each value to a fill
// color.
enum class ProductionStatus
{
    Unconfigured,  // no recipe/schematic selected (grey)
    Producing,     // a production cycle is active (green)
    Starved,       // idle: a required input is missing / Salvage Bay empty (red)
    Blocked,       // idle: output buffer full, inputs otherwise present (yellow)
};

// The rules deciding what a building can produce and whether it can start.
// Pure functions of the config and the building itself — they read no factory
// state, so they are free functions rather than BuildingSystem members.

// The recipe this building runs, or null when it has none selected. Every building type
// holds exactly one, a Smelter and a Reprocessing Plant included -- they only differ in
// how theirs first gets set (REQ-BLD-AUTO-RECIPE).
const RecipeDef* getSelectedRecipe(const GameConfig& config, const Building& b);

// The recipe an auto-recipe building adopts when this material is offered to it while it
// has none: the first recipe of its type, in config order, that consumes the material
// (REQ-BLD-AUTO-RECIPE). Null when no recipe of the type takes it.
const RecipeDef* findAutoRecipeFor(const GameConfig& config, BuildingType type,
                                   const ItemType& item);

// True when the building's input buffer holds every ingredient the recipe needs.
bool recipeInputsAvailable(const Building& b, const RecipeDef& recipe);

// Total materials a shipyard needs for its schematic plus its placed modules
// (REQ-BLD-SHIPYARD), keyed by item id.
std::map<std::string, int> computeShipyardRequiredMaterials(const GameConfig& config,
                                                            const Building& b);

// The same sum over a stored configuration rather than an operational building, so a
// construction site's schematic can be costed before it is built (REQ-BLD-SITE-CONFIG).
std::map<std::string, int> computeShipyardRequiredMaterials(
    const GameConfig& config, const std::string& recipeId,
    const std::optional<ShipLayoutConfig>& shipLayout);

// The ship's base production time plus that of every module in the configured layout
// (REQ-MOD-PRODUCTION-TIME), over a stored configuration as above.
double computeShipyardProductionTimeSeconds(
    const GameConfig& config, const std::string& recipeId,
    const std::optional<ShipLayoutConfig>& shipLayout);

// True when a production cycle could start right now, ignoring output-buffer space.
bool hasInputsToStart(const GameConfig& config, const Building& b);

// True when the building can take `itemCount` more items of `type` beside what it
// already holds of it. An emerging item has not left the building yet and so still
// counts against that material's capacity (REQ-MAT-OUTPUT-EMERGE, REQ-MAT-OUTPUT-BUFFER).
bool outputBufferHasRoom(const Building& b, const ItemType& type, int itemCount);

// True when every one of the recipe's output groups would fit -- the gate a cycle has to
// pass before it may start (REQ-MAT-CYCLE, REQ-MAT-OUTPUT-GROUP). With a single group that
// is simply that group. With several the pick is committed the moment the cycle starts, so
// every outcome must fit: testing all of them rather than the picked one is what keeps a
// stalled output belt from biasing the distribution.
bool recipeOutputsFit(const Building& b, const RecipeDef& recipe);

// True when a production cycle could actually start right now: some candidate recipe
// has its inputs *and* passes recipeOutputsFit (REQ-MAT-CYCLE). Stricter than
// hasInputsToStart, which looks at the input buffers alone.
bool canStartCycle(const GameConfig& config, const Building& b);

// Status light for a building, or nullopt for types that show none — belts,
// splitters, tunnels, HQ and defence stations (REQ-UI-STATUS-LIGHT).
std::optional<ProductionStatus> getProductionStatus(const GameConfig& config,
                                                    const Building& building);
