import pytest

from datatypes.epc.construction_age_band import EpcConstructionAgeBand
from datatypes.epc.walls import EpcWallDescriptions
from datatypes.epc.efficiency import EpcEfficiency

from backend.onboarders.mappings.parity.walls import resolve_wall_efficiency
from backend.onboarders.mappings.parity.as_built_wall_classifiers import (
    map_cavity_wall_insulation,
    map_solid_wall_insulation,
    map_timber_frame_wall_insulation,
    map_system_build_wall_insulation,
    map_granite_wall_insulation,
    map_sandstone_wall_insulation,
    map_cob_wall_insulation,
)


# ---------------------------------------------------------------------
# As-built wall description classification
# ---------------------------------------------------------------------

@pytest.mark.parametrize(
    "age_band, expected",
    [
        (EpcConstructionAgeBand.before_1900, EpcWallDescriptions.cavity_no_insulation_assumed),
        (EpcConstructionAgeBand.from_1950_to_1966, EpcWallDescriptions.cavity_no_insulation_assumed),
        (EpcConstructionAgeBand.from_1976_to_1982, EpcWallDescriptions.cavity_partial_insulated_assumed),
        (EpcConstructionAgeBand.from_1983_to_1990, EpcWallDescriptions.cavity_insulated_assumed),
        (EpcConstructionAgeBand.from_2023_onwards, EpcWallDescriptions.cavity_insulated_assumed),
    ],
)
def test_map_cavity_wall_insulation(age_band, expected):
    assert map_cavity_wall_insulation(age_band) == expected


@pytest.mark.parametrize(
    "age_band, expected",
    [
        (EpcConstructionAgeBand.before_1900, EpcWallDescriptions.solid_brick_no_insulation_assumed),
        (EpcConstructionAgeBand.from_1976_to_1982, EpcWallDescriptions.solid_brick_partial_insulated_assumed),
        (EpcConstructionAgeBand.from_1996_to_2002, EpcWallDescriptions.solid_brick_insulated_assumed),
    ],
)
def test_map_solid_wall_insulation(age_band, expected):
    assert map_solid_wall_insulation(age_band) == expected


@pytest.mark.parametrize(
    "age_band, expected",
    [
        (EpcConstructionAgeBand.before_1900, EpcWallDescriptions.timber_frame_no_insulation_assumed),
        (EpcConstructionAgeBand.from_1950_to_1966, EpcWallDescriptions.timber_frame_partial_insulated_assumed),
        (EpcConstructionAgeBand.from_1983_to_1990, EpcWallDescriptions.timber_frame_insulated_assumed),
    ],
)
def test_map_timber_frame_wall_insulation(age_band, expected):
    assert map_timber_frame_wall_insulation(age_band) == expected


@pytest.mark.parametrize(
    "age_band, expected",
    [
        (EpcConstructionAgeBand.before_1900, EpcWallDescriptions.system_no_insulation_assumed),
        (EpcConstructionAgeBand.from_1976_to_1982, EpcWallDescriptions.system_partial_insulated_assumed),
        (EpcConstructionAgeBand.from_2003_to_2006, EpcWallDescriptions.system_insulated_assumed),
    ],
)
def test_map_system_wall_insulation(age_band, expected):
    assert map_system_build_wall_insulation(age_band) == expected


@pytest.mark.parametrize(
    "age_band, expected",
    [
        (EpcConstructionAgeBand.before_1900, EpcWallDescriptions.granite_whinstone_no_insulation_assumed),
        (EpcConstructionAgeBand.from_1976_to_1982, EpcWallDescriptions.granite_whinstone_partial_insulated_assumed),
        (EpcConstructionAgeBand.from_2012_to_2022, EpcWallDescriptions.granite_whinestone_insulated_assumed),
    ],
)
def test_map_granite_wall_insulation(age_band, expected):
    assert map_granite_wall_insulation(age_band) == expected


@pytest.mark.parametrize(
    "age_band, expected",
    [
        (EpcConstructionAgeBand.before_1900, EpcWallDescriptions.sandstone_limestone_no_insulation_assumed),
        (EpcConstructionAgeBand.from_1976_to_1982, EpcWallDescriptions.sandstone_limestone_partial_insulated_assumed),
        (EpcConstructionAgeBand.from_2007_to_2011, EpcWallDescriptions.sandstone_limestone_insulated_assumed),
    ],
)
def test_map_sandstone_wall_insulation(age_band, expected):
    assert map_sandstone_wall_insulation(age_band) == expected


@pytest.mark.parametrize(
    "age_band, expected",
    [
        (EpcConstructionAgeBand.before_1900, EpcWallDescriptions.cob_as_built_average),
        (EpcConstructionAgeBand.from_1976_to_1982, EpcWallDescriptions.cob_as_built_average),
        (EpcConstructionAgeBand.from_1983_to_1990, EpcWallDescriptions.cob_as_built_good),
    ],
)
def test_map_cob_wall_insulation(age_band, expected):
    assert map_cob_wall_insulation(age_band) == expected


# ---------------------------------------------------------------------
# Wall efficiency resolution
# ---------------------------------------------------------------------

@pytest.mark.parametrize(
    "description, age_band, expected",
    [
        # Fixed efficiencies
        (EpcWallDescriptions.cavity_no_insulation_assumed, None, EpcEfficiency.POOR),
        (EpcWallDescriptions.cavity_partial_insulated_assumed, None, EpcEfficiency.AVERAGE),
        (EpcWallDescriptions.cavity_insulated_assumed, None, EpcEfficiency.GOOD),

        # Function-based efficiencies
        (
            EpcWallDescriptions.cavity_filled_cavity,
            EpcConstructionAgeBand.from_2023_onwards,
            EpcEfficiency.VERY_GOOD,
        ),
        (
            EpcWallDescriptions.cavity_filled_cavity,
            EpcConstructionAgeBand.from_1991_to_1995,
            EpcEfficiency.GOOD,
        ),
        (
            EpcWallDescriptions.solid_brick_internal_insulation,
            EpcConstructionAgeBand.from_2003_to_2006,
            EpcEfficiency.VERY_GOOD,
        ),
        (
            EpcWallDescriptions.solid_brick_internal_insulation,
            EpcConstructionAgeBand.from_1950_to_1966,
            EpcEfficiency.GOOD,
        ),
    ],
)
def test_resolve_wall_efficiency(description, age_band, expected):
    assert resolve_wall_efficiency(description, age_band) == expected


@pytest.mark.parametrize(
    "description",
    [
        EpcWallDescriptions.cavity_as_built_unknown,
        EpcWallDescriptions.solid_brick_as_built_unknown,
        EpcWallDescriptions.system_as_built_unknown,
        EpcWallDescriptions.timber_frame_as_built_unknown,
        EpcWallDescriptions.granite_as_built_unknown,
        EpcWallDescriptions.sandstone_as_built_unknown,
        EpcWallDescriptions.cob_as_built_unknown,
    ],
)
def test_unknown_wall_descriptions_return_na(description):
    assert resolve_wall_efficiency(description, None) == EpcEfficiency.NA
