import pytest
from functions import Balloon
import numpy as np

# Define the array of test cases
test_cases = [
    {
        "params": {
            "payload": 10684,
            "altitude": 35000,
            "film_density": 0.17,
            "tape_density": 0.1,
            "number_of_gores": 175,
            "pressure_difference": 0,
            "incremental_parameter": 1,
            "initial_theta": 50 * (np.pi / 180),
            "theta_end_error_tolerance": 1e-8,
            "max_iterations_balloon_shape": 10000000,
            "max_iterations_optimization": 100,
        },
        # Expected values
        "expected_radius_max": 40.72210509297562,
        "expected_height": 73.08134039750395,
        "expected_volume": 229125.38378046677,
        "expected_lift": 18456.22447248219,
        "expected_tapes_weight": 2092.116126408197,
        "expected_skin_weight": 3129.680053698512,
        "expected_sigma": 127.72795480744074,
        "expected_sigma_total": 2.054843560597019,
    },
    {
        "params": {
            "payload": 2000,
            "altitude": 25000,
            "film_density": 0.25,
            "tape_density": 0.2,
            "number_of_gores": 150,
            "pressure_difference": 100,
            "incremental_parameter": 1,
            "initial_theta": 80 * (np.pi / 180),
            "theta_end_error_tolerance": 1e-8,
            "max_iterations_balloon_shape": 10000000,
            "max_iterations_optimization": 100,
        },
        # Expected values
        "expected_radius_max": 16.17011583418943,
        "expected_height": 19.727704092888786,
        "expected_volume": 11779.92443498701,
        "expected_lift": 4559.142745428829,
        "expected_tapes_weight": 1279.4068003428001,
        "expected_skin_weight": 649.7174323676142,
        "expected_sigma": 1308.8015969483401,
        "expected_sigma_total": 3.2854511741941193,
    },
    {
        "params": {
            "payload": 8500,
            "altitude": 45000,
            "film_density": 0.2,
            "tape_density": 0.075,
            "number_of_gores": 250,
            "pressure_difference": 0,
            "incremental_parameter": 5,
            "initial_theta": 50 * (np.pi / 180),
            "theta_end_error_tolerance": 1e-8,
            "max_iterations_balloon_shape": 10000000,
            "max_iterations_optimization": 100,
        },
        "expected_radius_max": 81.39807626629876,
        "expected_height": 126.68895243478147,
        "expected_volume": 1679366.8896774151,
        "expected_lift": 30982.746049935035,
        "expected_tapes_weight": 4251.393467264736,
        "expected_skin_weight": 13949.912035888614,
        "expected_sigma": 84.13358069936513,
        "expected_sigma_total": 1.754169693045257,
    },
    # Add more test cases as needed
]


@pytest.mark.parametrize("case", test_cases)
def test_balloon(case):
    params = case["params"]

    balloon = Balloon(**params)

    tolerance_length = 0.01  # Tolerance of 0.01 meters
    tolerance_volume = 0.5  # Tolerance of 0.5 cubic meters
    tolerance_weight = 0.1  # Tolerance of 0.1 N
    tolerance_general = 0.05  # General tolerance
    _, sigma_meridional, _, _, sigma_total = balloon.get_meridional_stress(
        max_stress_film=1, max_stress_tape=1
    )

    assert max(balloon.radius) == pytest.approx(
        case["expected_radius_max"], abs=tolerance_length
    ), f"Failed for params: {params}"
    assert balloon.height[-1] == pytest.approx(
        case["expected_height"], abs=tolerance_length
    ), f"Failed for params: {params}"
    assert balloon.volume == pytest.approx(
        case["expected_volume"], abs=tolerance_volume
    ), f"Failed for params: {params}"
    assert balloon.lift == pytest.approx(
        case["expected_lift"], abs=tolerance_weight
    ), f"Failed for params: {params}"
    assert balloon.gores_weight == pytest.approx(
        case["expected_tapes_weight"], abs=tolerance_weight
    ), f"Failed for params: {params}"
    assert balloon.skin_weight == pytest.approx(
        case["expected_skin_weight"], abs=tolerance_weight
    ), f"Failed for params: {params}"
    assert np.median(sigma_meridional) == pytest.approx(
        case["expected_sigma"], abs=tolerance_general
    ), f"Failed for params: {params}"
    assert np.median(sigma_total) == pytest.approx(
        case["expected_sigma_total"], abs=tolerance_general
    ), f"Failed for params: {params}"
