from __future__ import annotations

import pytest

from models import MiningOperationType, Project, Scenario, ScenarioStatus
from services.pricing import PricingInput, PricingMetadata
from services.scenario_evaluation import ScenarioPricingConfig, ScenarioPricingEvaluator


def build_scenario() -> Scenario:
    project = Project(name="Test Project",
                      operation_type=MiningOperationType.OPEN_PIT)
    scenario = Scenario(
        project=project,
        project_id=1,
        name="Scenario A",
        status=ScenarioStatus.ACTIVE,
        currency="USD",
    )
    scenario.id = 1  # simulate persisted entity
    return scenario


def test_scenario_pricing_evaluator_uses_metadata_defaults() -> None:
    scenario = build_scenario()
    evaluator = ScenarioPricingEvaluator(
        ScenarioPricingConfig(
            metadata=PricingMetadata(
                default_currency="USD", default_payable_pct=95)
        )
    )
    inputs = [
        PricingInput(
            metal="copper",
            ore_tonnage=50_000,
            head_grade_pct=1.0,
            recovery_pct=90,
            payable_pct=None,
            reference_price=9_000,
            treatment_charge=50_000,
            smelting_charge=10_000,
            moisture_pct=9,
            moisture_threshold_pct=None,
            moisture_penalty_per_pct=None,
            impurity_ppm={"As": 120},
            premiums=10_000,
            fx_rate=1.0,
            currency_code=None,
        )
    ]

    snapshot = evaluator.evaluate(scenario, inputs=inputs)

    assert snapshot.scenario_id == scenario.id
    assert len(snapshot.results) == 1
    result = snapshot.results[0]
    assert result.currency == "USD"
    assert result.net_revenue > 0


def test_scenario_pricing_evaluator_override_metadata() -> None:
    scenario = build_scenario()
    evaluator = ScenarioPricingEvaluator(ScenarioPricingConfig())
    metadata_override = PricingMetadata(
        default_currency="CAD",
        default_payable_pct=90,
        moisture_threshold_pct=5,
        moisture_penalty_per_pct=500,
    )

    inputs = [
        PricingInput(
            metal="copper",
            ore_tonnage=20_000,
            head_grade_pct=1.2,
            recovery_pct=88,
            payable_pct=None,
            reference_price=8_200,
            treatment_charge=15_000,
            smelting_charge=6_000,
            moisture_pct=6,
            moisture_threshold_pct=None,
            moisture_penalty_per_pct=None,
            premiums=5_000,
            fx_rate=1.0,
            currency_code="cad",
        ),
        PricingInput(
            metal="gold",
            ore_tonnage=5_000,
            head_grade_pct=2.0,
            recovery_pct=90,
            payable_pct=None,
            reference_price=60_000,
            treatment_charge=10_000,
            smelting_charge=5_000,
            moisture_pct=4,
            moisture_threshold_pct=None,
            moisture_penalty_per_pct=None,
            premiums=15_000,
            fx_rate=1.0,
            currency_code="cad",
        ),
    ]

    snapshot = evaluator.evaluate(
        scenario,
        inputs=inputs,
        metadata_override=metadata_override,
    )

    assert len(snapshot.results) == 2
    assert all(result.currency ==
               scenario.currency for result in snapshot.results)

    copper_result = snapshot.results[0]
    expected_payable = 20_000 * 0.012 * 0.88 * 0.90
    assert copper_result.payable_metal_tonnes == pytest.approx(
        expected_payable)
    assert sum(result.net_revenue for result in snapshot.results) > 0
