#include "catch.hpp"

#include "ConfigLoader.h"
#include "ModulesConfig.h"
#include "TestConfig.h"

static const ModuleDef* findModule(const GameConfig& cfg, const std::string& id)
{
    for (const ModuleDef& m : cfg.modules.modules)
    {
        if (m.id == id) { return &m; }
    }
    return nullptr;
}

static const ModuleStatModifier* findModifier(const ModuleDef& def, const std::string& stat)
{
    for (const ModuleStatModifier& sm : def.statModifiers)
    {
        if (sm.stat == stat) { return &sm; }
    }
    return nullptr;
}

TEST_CASE("ConfigLoader: loadModules parses modules.toml", "[config][modules]")
{
    const GameConfig cfg = loadTestConfig();
    REQUIRE(cfg.modules.modules.size() >= 2);

    const ModuleDef& armor = cfg.modules.modules[0];
    CHECK(armor.id == "armor_plate");
    CHECK(armor.surfaceMask.size() == 1);
    CHECK(armor.surfaceMask[0] == "OO");
    CHECK(armor.materials.size() == 1);
    CHECK(armor.materials[0].item == "iron_ingot");
    CHECK(armor.materials[0].amount == 2);
    CHECK(armor.productionTimeSeconds == Approx(3.0));
    CHECK(armor.fillColor == "#808080");
    CHECK(armor.glyph == "A");
    REQUIRE(armor.statModifiers.size() == 1);
    CHECK(armor.statModifiers[0].stat == "hp");
    CHECK(armor.statModifiers[0].modifierType == "multiplicative");
    CHECK(armor.statModifiers[0].value == Approx(1.5));
}

TEST_CASE("ConfigLoader: loadModules parses additive modifiers", "[config][modules]")
{
    const GameConfig cfg = loadTestConfig();
    REQUIRE(cfg.modules.modules.size() >= 2);

    const ModuleDef& sensor = cfg.modules.modules[1];
    CHECK(sensor.id == "sensor_booster");
    REQUIRE(sensor.statModifiers.size() == 1);
    CHECK(sensor.statModifiers[0].stat == "sensor_range");
    CHECK(sensor.statModifiers[0].modifierType == "additive");
    CHECK(sensor.statModifiers[0].value == Approx(100.0));
}

TEST_CASE("ConfigLoader: multiplicative modifier with unit suffix is parsed (weapon_primer)", "[config][modules]")
{
    const GameConfig cfg = loadTestConfig();
    const ModuleDef* primer = findModule(cfg, "weapon_primer");
    REQUIRE(primer != nullptr);
    REQUIRE(primer->statModifiers.size() == 1);
    const ModuleStatModifier* sm = findModifier(*primer, "attack_rate");
    REQUIRE(sm != nullptr);
    CHECK(sm->modifierType == "multiplicative");
    CHECK(sm->value == Approx(1.2));
}

TEST_CASE("ConfigLoader: weapon_stabilizer parses two multiplicative weapon modifiers", "[config][modules]")
{
    const GameConfig cfg = loadTestConfig();
    const ModuleDef* stab = findModule(cfg, "weapon_stabilizer");
    REQUIRE(stab != nullptr);
    REQUIRE(stab->statModifiers.size() == 2);

    const ModuleStatModifier* rangeMod = findModifier(*stab, "attack_range");
    REQUIRE(rangeMod != nullptr);
    CHECK(rangeMod->modifierType == "multiplicative");
    CHECK(rangeMod->value == Approx(1.5));

    const ModuleStatModifier* rateMod = findModifier(*stab, "attack_rate");
    REQUIRE(rateMod != nullptr);
    CHECK(rateMod->modifierType == "multiplicative");
    CHECK(rateMod->value == Approx(0.8));
}

TEST_CASE("ConfigLoader: afterburner parses multiplicative speed and additive main_acceleration", "[config][modules]")
{
    const GameConfig cfg = loadTestConfig();
    const ModuleDef* ab = findModule(cfg, "afterburner");
    REQUIRE(ab != nullptr);
    REQUIRE(ab->statModifiers.size() == 2);

    const ModuleStatModifier* speedMod = findModifier(*ab, "speed");
    REQUIRE(speedMod != nullptr);
    CHECK(speedMod->modifierType == "multiplicative");
    CHECK(speedMod->value == Approx(1.6));

    const ModuleStatModifier* accelMod = findModifier(*ab, "main_acceleration");
    REQUIRE(accelMod != nullptr);
    CHECK(accelMod->modifierType == "additive");
    CHECK(accelMod->value == Approx(60.0));
}

TEST_CASE("ConfigLoader: maneuvering_thrusters parses multiplicative speed and additive maneuvering_acceleration", "[config][modules]")
{
    const GameConfig cfg = loadTestConfig();
    const ModuleDef* mt = findModule(cfg, "maneuvering_thrusters");
    REQUIRE(mt != nullptr);
    REQUIRE(mt->statModifiers.size() == 2);

    const ModuleStatModifier* speedMod = findModifier(*mt, "speed");
    REQUIRE(speedMod != nullptr);
    CHECK(speedMod->modifierType == "multiplicative");
    CHECK(speedMod->value == Approx(1.2));

    const ModuleStatModifier* accelMod = findModifier(*mt, "maneuvering_acceleration");
    REQUIRE(accelMod != nullptr);
    CHECK(accelMod->modifierType == "additive");
    CHECK(accelMod->value == Approx(10.0));
}

TEST_CASE("ConfigLoader: loadShips parses layout field", "[config][ships]")
{
    const GameConfig cfg = loadTestConfig();
    REQUIRE(!cfg.ships.ships.empty());

    const ShipDef& ship = cfg.ships.ships[0];
    REQUIRE(!ship.layout.empty());
    CHECK(ship.layout[0] == "XOX");
    CHECK(ship.layout[1] == "OOO");
    CHECK(ship.layout[2] == "XOX");
}
