#pragma once

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

#include "BuildingType.h"

// One entry in [[recipe]].inputs — amount units of a named item consumed per
// production cycle (REQ-MAT-CYCLE).
struct RecipeIngredient
{
    std::string item;
    int amount;
};

// One entry in [[recipe]].outputs. For reprocessing_plant recipes, probability
// is populated and outputs are rolled with weighted pick at cycle start
// (REQ-BLD-REPROCESSING, REQ-MAT-CYCLE). For other buildings, probability is
// std::nullopt and all outputs are produced on every cycle.
struct RecipeOutput
{
    std::string item;
    int amount;
    std::optional<double> probability;
};

struct RecipeDef
{
    std::string id;                // Unique recipe id; used by UI for selection.
    BuildingType building;         // Which BuildingType can run this recipe.
    std::vector<RecipeIngredient> inputs;
    std::vector<RecipeOutput> outputs;
    double durationSeconds;
    // Optional id of the item whose icon represents this recipe in the recipe-
    // selection dialog (REQ-UI-RECIPE-ICON). When unset, the first output item is
    // used. A missing icon file for that item is not an error (REQ-UI-ITEM-ICON).
    std::optional<std::string> icon;
    // Assembler only. When true, this recipe is available from game start
    // regardless of the implicit item graph — used for base recipes that no
    // schematic's materials reach (e.g. building blocks). See REQ-LOCK-IMPLICIT.
    // Otherwise an assembler recipe is either explicitly gated (granted by an
    // unlock group, REQ-LOCK-EXPLICIT) or implicitly gated via the item graph.
    bool unlockedAtStart = false;
};

struct RecipesConfig
{
    std::vector<RecipeDef> recipes;

    // Returns the definition for the given recipe id, or nullptr if the id has
    // no entry in recipes.toml.
    const RecipeDef* findRecipeDef(const std::string& id) const
    {
        for (const RecipeDef& recipe : recipes)
        {
            if (recipe.id == id)
            {
                return &recipe;
            }
        }
        return nullptr;
    }

    // Same, but additionally requires the recipe to belong to the given building
    // type — recipe ids are only unique per building type.
    const RecipeDef* findRecipeDef(const std::string& id, BuildingType building) const
    {
        for (const RecipeDef& recipe : recipes)
        {
            if (recipe.id == id && recipe.building == building)
            {
                return &recipe;
            }
        }
        return nullptr;
    }
};
