#pragma once

#include <optional>

#include <QPoint>

#include "BuildingId.h"
#include "BuildingType.h"
#include "Rotation.h"
#include "FactoryState.h"
#include "Simulation.h"

class BeltSystem;
class BuildingSystem;

// Test-only backdoor to Simulation's private player-action mutators and mutable
// subsystem accessors. Declared a friend of Simulation, so it can hand tests the
// same mutation surface that Simulation::apply uses internally — without exposing
// those mutators to production (UI/app) code, which must go through the command
// chokepoint (docs/replay_design.md).
//
// This header lives under src/test and is not on the lib/ui/app include path, so
// only test translation units can reach it. Non-player test setup that has no
// command equivalent (e.g. placeImmediate, forEachBuilding buffer injection) is
// reached via buildings(sim)/belts(sim).
struct SimulationTestAccess
{
    static BuildingSystem& buildings(Simulation& sim) { return sim.getBuildingsMutable(); }
    static FactoryState&   state(Simulation& sim)     { return sim.m_factoryState; }
    static BeltSystem&     belts(Simulation& sim)     { return sim.getBeltsMutable(); }

    static std::optional<BuildingId> place(Simulation& sim, BuildingType type,
                                           QPoint anchor, Rotation rotation)
    {
        return sim.tryPlaceBuilding(type, anchor, rotation);
    }

    static void deconstruct(Simulation& sim, BuildingId id) { sim.deconstruct(id); }

    static void cancelDeconstruction(Simulation& sim, BuildingId id)
    {
        sim.cancelDeconstruction(id);
    }

    static void applySchematicChoice(Simulation& sim, int choiceIndex)
    {
        sim.applySchematicChoice(choiceIndex);
    }
};
