from typing import Callable
import pytest
from datetime import datetime

from backend.app.domain.classes.plan import Plan
from backend.app.domain.classes.scenario import Scenario
from backend.app.domain.records.plan_record import PlanRecord
from backend.app.domain.records.scenario_record import ScenarioRecord
from backend.app.db.models.portfolio import PortfolioGoal
from datatypes.epc.domain.epc import Epc


@pytest.fixture
def created_at_datetime() -> datetime:
    return datetime.now()


@pytest.fixture
def epc_c_scenario(created_at_datetime: datetime) -> "Scenario":
    # arrange
    scenario_record = ScenarioRecord(
        name="EPC C",
        created_at=created_at_datetime,
        housing_type="",
        goal=PortfolioGoal.INCREASING_EPC,
        goal_value="C",
        trigger_file_path="",
        multi_plan=False,
        is_default=False,
    )
    return Scenario(record=scenario_record, id=1)


@pytest.fixture
def plan_factory(
    epc_c_scenario: "Scenario", created_at_datetime: datetime
) -> Callable[[int, "Epc"], "Plan"]:
    # returns a function to create plans with different attributes
    def _create_plan(post_sap_points: int, post_epc_rating: "Epc") -> "Plan":
        plan_record = PlanRecord(
            property_id=1,
            portfolio_id=1,
            created_at=created_at_datetime,
            is_default=False,
            post_sap_points=post_sap_points,
            post_epc_rating=post_epc_rating,
        )
        return Plan(record=plan_record, scenario=epc_c_scenario, id=1)

    return _create_plan


@pytest.mark.parametrize(
    "post_sap_points, post_epc_rating, expected_compliance",
    [
        (75, Epc.C, True),
        (100, Epc.A, True),
        (60, Epc.D, False),
    ],
)
def test_scenario_goal_is_epc_c(
    plan_factory: Callable[[int, "Epc"], "Plan"],
    post_sap_points: int,
    post_epc_rating: "Epc",
    expected_compliance: bool,
) -> None:
    # arrange
    plan = plan_factory(post_sap_points, post_epc_rating)

    # act
    actual_compliance: bool = plan.is_compliant

    # assert
    assert actual_compliance == expected_compliance
