// tests/test_rocket_simulator.cpp

#include "vendor/catch_amalgamated.hpp"
#include "Rocket.h"
#include "Stage.h"
#include "Motor.h"
#include "Airframe.h"
#include "FinSet.h"
#include "RecoverySystem.h"
#include "Environment.h"
#include "FlightSimulator.h"
#include "FlightState.h"
#include "Integrator.h"

// Bring Approx into scope
using Catch::Approx;

TEST_CASE("Rocket and FlightSimulator integration test", "[integration]") {
    // Setup Environment
    auto environment = std::make_shared<Environment>(
        101325.0, // surface pressure (Pa)
        288.15,   // surface temperature (K)
        0.0       // launch altitude (m)
    );

    // Setup Rocket
    auto rocket = std::make_shared<Rocket>("IntegrationTestRocket");

    auto stage = std::make_unique<Stage>("Stage1");

    // Motor
    auto motor = std::make_unique<Motor>("TestMotor", 0.05, 50.0); // 50g propellant
    motor->addThrustDataPoint(0.0, 0.0);
    motor->addThrustDataPoint(0.1, 50.0);
    motor->addThrustDataPoint(1.5, 50.0);
    motor->addThrustDataPoint(1.6, 0.0);
    stage->addMotor(std::move(motor));

    // Airframe
    auto airframe = std::make_unique<Airframe>("Airframe1",
        1.5,  // length
        0.1,  // diameter
        2.0,  // dry mass
        0.75  // drag coefficient
    );
    stage->setAirframe(std::move(airframe));

    // FinSet
    auto finset = std::make_unique<FinSet>("TestFins",
        3,      // 3 fins
        0.15,   // root chord
        0.10,   // tip chord
        0.10,   // span
        0.05,   // sweep
        0.003,  // thickness
        500.0   // density
    );
    stage->setFinSet(std::move(finset));

    // Recovery
    auto recovery = std::make_unique<RecoverySystem>("MainChute",
        RecoverySystem::DeploymentType::Apogee,
        0.0,    // no trigger value needed
        1.5,    // Cd
        2.0     // area
    );
    stage->setRecoverySystem(std::move(recovery));

    rocket->addStage(std::move(stage));
    rocket->updateMassProperties();

    // Setup FlightSimulator
    FlightSimulator simulator(rocket, environment);

    SECTION("Full flight simulation runs and reaches apogee") {
        simulator.run(20.0, 0.01); // Simulate 20 seconds with 10ms step

        const auto& flightLog = simulator.getFlightLog();

        REQUIRE(flightLog.size() > 0);

        double maxAltitude = 0.0;
        double landingAltitude = flightLog.back().getPosition()[2];

        for (const auto& state : flightLog) {
            double alt = state.getPosition()[2];
            if (alt > maxAltitude) {
                maxAltitude = alt;
            }
        }

        REQUIRE(maxAltitude > 0.0);           // Rocket climbed
        REQUIRE(landingAltitude <= 1.0);       // Rocket landed (near ground)

        // Optional: check that apogee was reached early in flight
        size_t apogeeIndex = 0;
        for (size_t i = 1; i < flightLog.size(); ++i) {
            if (flightLog[i].getPosition()[2] < flightLog[i-1].getPosition()[2]) {
                apogeeIndex = i - 1;
                break;
            }
        }

        REQUIRE(apogeeIndex > 0); // Apogee was found
    }
}
