import pytest
from unittest.mock import Mock
from backend.Property import Property
from etl.epc.Record import EPCRecord
from recommendations.RoofRecommendations import RoofRecommendations
from recommendations.tests.test_data.materials import materials


class TestRoofRecommendations:

    def test_null_roof_description(self):
        epc_record = EPCRecord(county="Cambridgeshire")
        property_instance = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance.age_band = "F"
        property_instance.insulation_floor_area = 100
        property_instance.roof = {
            'original_description': None,
            'clean_description': None,
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': 'none', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': None
        }
        property_instance.already_installed = []

        roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)
        roof_recommender.recommend(phase=0)

        assert not roof_recommender.recommendations

    def test_loft_insulation_recommendation_no_insulation(self):
        epc_record = EPCRecord(county="Cambridgeshire")
        property_instance = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance.age_band = "F"
        property_instance.insulation_floor_area = 100
        property_instance.roof = {
            'original_description': 'Pitched, no insulation (assumed)',
            'clean_description': 'Pitched, no insulation',
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': 'none', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
        }
        property_instance.already_installed = []

        roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)

        assert not roof_recommender.recommendations

        roof_recommender.recommend(phase=0)

        assert len(roof_recommender.recommendations) == 3
        assert roof_recommender.recommendations[0]["parts"][0]["depth"] == 300

    def test_loft_insulation_recommendation_50mm_insulation(self):
        epc_record = EPCRecord(county="Kent", **{"roof_energy_eff": "Very Poor"})
        property_instance2 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance2.age_band = "F"
        property_instance2.insulation_floor_area = 100
        property_instance2.roof = {
            'original_description': 'Pitched, 50mm loft insulation (assumed)',
            'clean_description': 'Pitched, 50mm loft insulation',
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': '50', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
        }
        property_instance2.already_installed = []

        roof_recommender2 = RoofRecommendations(property_instance=property_instance2, materials=materials)

        assert not roof_recommender2.recommendations

        roof_recommender2.recommend(phase=0)

        assert len(roof_recommender2.recommendations) == 3

        assert roof_recommender2.recommendations[0]["total"] == 2100
        assert roof_recommender2.recommendations[0]["new_u_value"] == 0.13
        assert float(roof_recommender2.recommendations[0]["starting_u_value"]) == 0.68
        assert roof_recommender2.recommendations[0]["parts"][0]["depth"] == 300

        epc_record = EPCRecord(county="Greater London Authority", **{"roof_energy_eff": "Very Poor"})
        property_instance3 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance3.age_band = "F"
        property_instance3.insulation_floor_area = 100
        property_instance3.roof = {
            'original_description': 'Pitched, 50mm loft insulation (assumed)',
            'clean_description': 'Pitched, 50mm loft insulation',
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': '50', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
        }
        property_instance3.already_installed = []

        roof_recommender3 = RoofRecommendations(property_instance=property_instance3, materials=materials)

        assert not roof_recommender3.recommendations

        roof_recommender3.recommend(phase=0)

        assert roof_recommender3.recommendations
        assert len(roof_recommender3.recommendations) == 3
        assert roof_recommender3.recommendations[0]["parts"][0]["depth"] == 300.0

    def test_loft_insulation_recommendation_150mm_insulation(self):
        epc_record = EPCRecord(county="North East Lincolnshire", **{"roof_energy_eff": "Good"})
        property_instance4 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance4.age_band = "F"
        property_instance4.insulation_floor_area = 100
        property_instance4.roof = {
            'original_description': 'Pitched, 150mm loft insulation (assumed)',
            'clean_description': 'Pitched, 150mm loft insulation',
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': '150', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
        }
        property_instance4.already_installed = []

        roof_recommender4 = RoofRecommendations(property_instance=property_instance4, materials=materials)

        assert not roof_recommender4.recommendations

        roof_recommender4.recommend(phase=0, default_u_values=True)

        assert len(roof_recommender4.recommendations) == 3

        assert roof_recommender4.recommendations[0]["total"] == 2100.0
        assert float(roof_recommender4.recommendations[0]["new_u_value"]) == 0.14
        assert float(roof_recommender4.recommendations[0]["starting_u_value"]) == 0.3
        assert roof_recommender4.recommendations[0]["parts"][0]["depth"] == 300

        epc_record = EPCRecord(county="Somerset", **{"roof_energy_eff": "Good"})
        property_instance5 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance5.age_band = "F"
        property_instance5.insulation_floor_area = 100
        property_instance5.roof = {
            'original_description': 'Pitched, 150mm loft insulation (assumed)',
            'clean_description': 'Pitched, 150mm loft insulation',
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': '150', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
        }
        property_instance5.already_installed = []

        roof_recommender5 = RoofRecommendations(property_instance=property_instance5, materials=materials)

        assert not roof_recommender5.recommendations

        roof_recommender5.recommend(phase=0)

        assert roof_recommender5.recommendations
        assert len(roof_recommender5.recommendations) == 3
        assert roof_recommender5.recommendations[0]["parts"][0]["depth"] == 300

    def test_loft_insulation_recommendation_270mm_insulation(self):
        epc_record = EPCRecord(county="Portsmouth")
        property_instance6 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance6.age_band = "F"
        property_instance6.insulation_floor_area = 100
        property_instance6.roof = {
            'original_description': 'Pitched, 270mm loft insulation (assumed)',
            'clean_description': 'Pitched, 270mm loft insulation',
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': True, 'is_roof_room': False, 'is_loft': True, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': '270', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
        }
        property_instance6.already_installed = []

        roof_recommender6 = RoofRecommendations(property_instance=property_instance6, materials=materials)

        assert not roof_recommender6.recommendations

        roof_recommender6.recommend(phase=0)

        assert len(roof_recommender6.recommendations) == 0

    def test_uninsulated_room_in_roof(self):
        epc_record = EPCRecord(county="Southampton", roof_energy_eff="Very Poor")
        property_instance7 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance7.age_band = "F"
        property_instance7.insulation_floor_area = 100
        property_instance7.roof = {
            'original_description': 'Room-in-roof, no insulation (assumed)',
            'clean_description': 'Room-in-roof, no insulation',
            'thermal_transmittance': None,
            'thermal_transmittance_unit': None,
            'is_pitched': False, 'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': 'none', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': 'none'
        }
        property_instance7.already_installed = []

        property_instance7.pitched_roof_area = 110

        roof_recommender7 = RoofRecommendations(property_instance=property_instance7, materials=materials)

        assert not roof_recommender7.recommendations

        roof_recommender7.recommend(phase=0)

        assert len(roof_recommender7.recommendations) == 1
        assert roof_recommender7.recommendations[0]["new_u_value"] == 0.18
        assert roof_recommender7.recommendations[0]["starting_u_value"] == 0.8
        assert roof_recommender7.recommendations[0]["description"] == "Insulate room in roof at rafters and re-decorate"
        # Ensure all tests are room in roof
        assert all(rec["measure_type"] == "room_roof_insulation" for rec in roof_recommender7.recommendations)

    def test_ceiling_insulated_room_in_roof(self):
        epc_record = EPCRecord(county="Southampton", roof_energy_eff="Very Poor")
        property_instance8 = Property(id=8, address="fake", postcode="fake", epc_record=epc_record)
        property_instance8.age_band = "F"
        property_instance8.insulation_floor_area = 100
        property_instance8.roof = {
            'original_description': 'Roof room(s), ceiling insulated',
            'clean_description': 'Roof room(s), ceiling insulated',
            'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False,
            'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
            'is_at_rafters': False,
            'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': 'average'
        }
        property_instance8.already_installed = []

        property_instance8.pitched_roof_area = 110

        roof_recommender8 = RoofRecommendations(property_instance=property_instance8, materials=materials)

        assert not roof_recommender8.recommendations

        roof_recommender8.recommend(phase=0)

        # No recommendations in this case
        assert not roof_recommender8.recommendations

    def test_insulated_room_in_roof(self):
        epc_record = EPCRecord(county="Southampton", roof_energy_eff="Very Poor")
        property_instance9 = Property(id=9, address="fake", postcode="fake", epc_record=epc_record)
        property_instance9.age_band = "F"
        property_instance9.insulation_floor_area = 100
        property_instance9.roof = {
            'original_description': 'Roof room(s), insulated (assumed)',
            'clean_description': 'Roof room(s), insulated',
            'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False,
            'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False,
            'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'average'
        }
        property_instance9.already_installed = []

        property_instance9.pitched_roof_area = 110
        property_instance9.data = {"county": "Rutland"}

        roof_recommender9 = RoofRecommendations(property_instance=property_instance9, materials=materials)

        assert not roof_recommender9.recommendations

        roof_recommender9.recommend(phase=0)

        # No recommendations in this case
        assert not roof_recommender9.recommendations

    def test_limited_insulated_room_in_roof(self):
        epc_record = EPCRecord(county="Westmorland", roof_energy_eff="Poor")
        property_instance10 = Property(id=10, address="fake", postcode="fake", epc_record=epc_record)
        property_instance10.age_band = "F"
        property_instance10.insulation_floor_area = 100
        property_instance10.roof = {
            'original_description': 'Roof room(s), limited insulation (assumed)',
            'clean_description': 'Roof room(s), limited insulation',
            'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False,
            'is_roof_room': True, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False,
            'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
            'insulation_thickness': 'below average'
        }
        property_instance10.already_installed = []

        property_instance10.pitched_roof_area = 110

        roof_recommender10 = RoofRecommendations(property_instance=property_instance10, materials=materials)

        assert not roof_recommender10.recommendations

        roof_recommender10.recommend(phase=0)

        assert len(roof_recommender10.recommendations) == 1

        assert roof_recommender10.recommendations[0]["new_u_value"] == 0.17

        assert roof_recommender10.recommendations[0]["starting_u_value"] == 0.68

        assert (roof_recommender10.recommendations[0]["description"] ==
                'Insulate room in roof at rafters and re-decorate')

    def test_flat_no_insulation(self):
        epc_record = EPCRecord(county="Swindon")
        property_instance11 = Property(id=11, address="fake", postcode="fake", epc_record=epc_record)
        property_instance11.age_band = "D"
        property_instance11.insulation_floor_area = 33.5
        property_instance11.perimeter = 24
        property_instance11.roof = {
            'original_description': 'Flat, no insulation (assumed)',
            'clean_description': 'Flat, no insulation',
            'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False,
            'is_roof_room': False, 'is_loft': False, 'is_flat': True, 'is_thatched': False, 'is_at_rafters': False,
            'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'none'
        }
        property_instance11.already_installed = []

        roof_recommender11 = RoofRecommendations(property_instance=property_instance11, materials=materials)

        assert not roof_recommender11.recommendations

        roof_recommender11.recommend(phase=0)

        assert len(roof_recommender11.recommendations) == 1

        assert roof_recommender11.recommendations[0]["parts"][0]["depth"] == 150
        assert roof_recommender11.recommendations[0]["total"] == 6532.5
        assert roof_recommender11.recommendations[0]["new_u_value"] == 0.14
        assert roof_recommender11.recommendations[0]["starting_u_value"] == 2.3
        assert roof_recommender11.recommendations[0]["description"] == \
               "Insulate the home's flat roof with 150mm of Ecotherm Eco-Versal General Purpose Insulation Board"

    def test_flat_insulated(self):
        epc_record = EPCRecord(county="Thurrock")
        property_instance12 = Property(id=12, address="fake", postcode="fake", epc_record=epc_record)
        property_instance12.age_band = "D"
        property_instance12.insulation_floor_area = 40
        property_instance12.perimeter = 30

        property_instance12.roof = {
            'original_description': 'Flat, insulated (assumed)',
            'clean_description': 'Flat, insulated',
            'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False,
            'is_roof_room': False,
            'is_loft': False, 'is_flat': True, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True,
            'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'average'
        }
        property_instance12.already_installed = []

        roof_recommender12 = RoofRecommendations(property_instance=property_instance12, materials=materials)

        assert not roof_recommender12.recommendations

        roof_recommender12.recommend(phase=0)

        assert not roof_recommender12.recommendations

    def test_flat_limited_insulation(self):
        epc_record = EPCRecord(county="Tyne and Wear")
        property_instance13 = Property(id=12, address="fake", postcode="fake", epc_record=epc_record)
        property_instance13.age_band = "D"
        property_instance13.insulation_floor_area = 40
        property_instance13.perimeter = 40
        property_instance13.roof = {
            'original_description': 'Flat, limited insulation (assumed)',
            'clean_description': 'Flat, limited insulation',
            'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': False,
            'is_roof_room': False,
            'is_loft': False, 'is_flat': True, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True,
            'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'below average'
        }
        property_instance13.already_installed = []

        roof_recommender13 = RoofRecommendations(property_instance=property_instance13, materials=materials)

        assert not roof_recommender13.recommendations

        roof_recommender13.recommend(phase=0)

        assert len(roof_recommender13.recommendations) == 1

        assert roof_recommender13.recommendations[0]["parts"][0]["depth"] == 150

        assert roof_recommender13.recommendations[0]["total"] == 7800
        assert roof_recommender13.recommendations[0]["new_u_value"] == 0.14
        assert roof_recommender13.recommendations[0]["starting_u_value"] == 2.3

        assert roof_recommender13.recommendations[0]["description"] == \
               "Insulate the home's flat roof with 150mm of Ecotherm Eco-Versal General Purpose Insulation Board"

    def test_property_above(self):
        epc_record = EPCRecord(county="Suffolk")
        property_instance14 = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
        property_instance14.age_band = "F"
        property_instance14.insulation_floor_area = 100
        property_instance14.roof = {
            'original_description': '(other premises above)',
            'clean_description': '(other premises above)', 'thermal_transmittance': 0,
            'thermal_transmittance_unit': 'w/m-¦k', 'is_pitched': False, 'is_roof_room': False,
            'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False,
            'is_assumed': False, 'has_dwelling_above': True, 'is_valid': True,
            'insulation_thickness': None
        }
        property_instance14.already_installed = []

        roof_recommender14 = RoofRecommendations(property_instance=property_instance14, materials=materials)

        assert not roof_recommender14.recommendations

        roof_recommender14.recommend(phase=0)

        assert not roof_recommender14.recommendations

    # ~~~~~~~~~~~~ Sloping Ceiling Insulation ~~~~~~~~~~~~
    @pytest.mark.parametrize(
        "roof, has_sloping_ceiling_recommendation, primary_roof_looks_sloped, insulation_thickness, "
        "has_loft_insulation_recommendation, expected_result",
        [
            (
                    {
                        'original_description': 'Pitched, no insulation',
                        'thermal_transmittance': None,
                        'thermal_transmittance_unit': None,
                        'is_pitched': True,
                        'is_roof_room': False,
                        'is_loft': False,
                        'is_flat': False,
                        'is_thatched': False,
                        'is_at_rafters': False,
                        'is_assumed': False,
                        'has_dwelling_above': False,
                        'is_valid': True,
                        'insulation_thickness': 'none'
                    },
                    True,
                    True,
                    "none",
                    False,
                    True,
            ),
            (
                    {
                        'original_description': 'Pitched, insulated (assumed)',
                        'clean_description': 'Pitched, insulated',
                        'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True,
                        'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
                        'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
                        'insulation_thickness': 'average'
                    },
                    False,
                    False,
                    "average",
                    False,
                    False
            )
        ]
    )
    def test_is_sloping_ceiling_appropriate(
        self, roof, has_sloping_ceiling_recommendation, primary_roof_looks_sloped,
        insulation_thickness, has_loft_insulation_recommendation, expected_result
    ):
        assert RoofRecommendations.is_sloping_ceiling_appropriate(
            is_flat=bool(roof["is_flat"]),
            is_pitched=bool(roof["is_pitched"]),
            is_loft=bool(roof["is_loft"]),
            is_assumed=bool(roof["is_assumed"]),
            has_sloping_ceiling_recommendation=has_sloping_ceiling_recommendation,
            primary_roof_looks_sloped=primary_roof_looks_sloped,
            insulation_thickness=insulation_thickness,
            has_loft_insulation_recommendation=has_loft_insulation_recommendation
        ) == expected_result

    def test_sloping_ceiling_pitched_no_insulation(self):
        property_instance = Mock(
            id=0,
            roof={
                'original_description': 'Pitched, no insulation', 'clean_description': 'Pitched, no insulation',
                'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True,
                'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
                'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True,
                'insulation_thickness': 'none'
            },
            roof_area=64.085,
            data={"county": None, "local-authority-label": "Manchester"},
            age_band="D",
            already_installed=[],
            non_invasive_recommendations=[
                {'type': 'flat_roof_insulation', 'sap_points': 9, 'survey': True},
                {'type': 'sloping_ceiling_insulation', 'sap_points': 9, 'survey': True},
                {'type': 'cavity_wall_insulation', 'sap_points': 6, 'survey': True},
                {'type': 'suspended_floor_insulation', 'sap_points': 2, 'survey': True},
                {'type': 'roomstat_programmer_trvs', 'sap_points': 3, 'survey': True},
                {'type': 'time_temperature_zone_control', 'sap_points': 3, 'survey': True},
                {'type': 'solar_pv', 'sap_points': 5, 'survey': True, 'suitable': True}
            ],
            find_my_epc_components=[
                {'component_name': 'Wall', 'description': 'Solid brick, as built, no insulation (assumed)',
                 'efficiency': 'Very poor', 'appearance_index': 0},
                {'component_name': 'Roof', 'description': 'Pitched, no insulation', 'efficiency': 'Very poor',
                 'appearance_index': 0},
                {'component_name': 'Roof', 'description': 'Pitched, limited insulation', 'efficiency': 'Very poor',
                 'appearance_index': 1},
                {'component_name': 'Window', 'description': 'Some multiple glazing', 'efficiency': 'Very poor',
                 'appearance_index': 0},
                {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas',
                 'efficiency': 'Good', 'appearance_index': 0},
                {'component_name': 'Main heating control', 'description': 'Programmer, room thermostat and TRVs',
                 'efficiency': 'Good', 'appearance_index': 0},
                {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good',
                 'appearance_index': 0},
                {'component_name': 'Lighting', 'description': 'Low energy lighting in 28% of fixed outlets',
                 'efficiency': 'Average', 'appearance_index': 0},
                {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A',
                 'appearance_index': 0},
                {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A',
                 'appearance_index': 0}
            ]

        )

        roof_recommender = RoofRecommendations(property_instance=property_instance, materials=[])
        assert not roof_recommender.recommendations

        roof_recommender.recommend(phase=0)
        assert len(roof_recommender.recommendations) == 1

        assert roof_recommender.recommendations[0]["type"] == "sloping_ceiling_insulation"
        assert roof_recommender.recommendations[0]["measure_type"] == "sloping_ceiling_insulation"
        assert (
            roof_recommender.recommendations[0]["description"] ==
            "Insulate sloping ceilings at the rafters and re-decorate"
        )
        assert roof_recommender.recommendations[0]["simulation_config"] == {
            'roof_insulation_thickness_ending': 'average',
            'roof_thermal_transmittance_ending': 0.5,
            'roof_energy_eff_ending': 'Average'
        }

        assert roof_recommender.recommendations[0]["description_simulation"] == {
            'roof-description': 'Pitched, insulated', 'roof-energy-eff': 'Average'
        }

    def test_ambiguous_sloping_ceiling_or_loft(self):
        # In this case, we actually expect loft insulation to be recommended
        property_instance = Mock(
            id=0,
            roof={
                # Roof looks like it could be a sloping ceiling but it's actually a loft
                'original_description': 'Pitched, no insulation', 'clean_description': 'Pitched, no insulation',
                'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True,
                'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
                'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True,
                'insulation_thickness': 'none'
            },
            roof_area=197.748,
            data={"county": None, "local-authority-label": "Manchester"},
            already_installed=[],
            find_my_epc_components=[
                {'component_name': 'Wall', 'description': 'Solid brick, as built, no insulation (assumed)',
                 'efficiency': 'Very poor', 'appearance_index': 0},
                {'component_name': 'Roof', 'description': 'Pitched, no insulation', 'efficiency': 'Very poor',
                 'appearance_index': 0},
                {'component_name': 'Roof', 'description': 'Pitched, limited insulation', 'efficiency': 'Very poor',
                 'appearance_index': 1},
                {'component_name': 'Window', 'description': 'Some multiple glazing', 'efficiency': 'Very poor',
                 'appearance_index': 0},
                {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas',
                 'efficiency': 'Good', 'appearance_index': 0},
                {'component_name': 'Main heating control', 'description': 'Programmer, room thermostat and TRVs',
                 'efficiency': 'Good', 'appearance_index': 0},
                {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good',
                 'appearance_index': 0},
                {'component_name': 'Lighting', 'description': 'Low energy lighting in 28% of fixed outlets',
                 'efficiency': 'Average', 'appearance_index': 0},
                {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A',
                 'appearance_index': 0},
                {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A',
                 'appearance_index': 0}
            ],
            age_band="B",
            non_invasive_recommendations=[
                {'type': 'loft_insulation', 'sap_points': 3, 'survey': True},
                {'type': 'flat_roof_insulation', 'sap_points': 2, 'survey': True},
                {'type': 'sloping_ceiling_insulation', 'sap_points': 2, 'survey': True},
                {'type': 'internal_wall_insulation', 'sap_points': 9, 'survey': True},
                {'type': 'draught_proofing', 'sap_points': 1, 'survey': True},
                {'type': 'low_energy_lighting', 'sap_points': 1, 'survey': True},
                {'type': 'solar_water_heating', 'sap_points': 1, 'survey': True},
                {'type': 'double_glazing', 'sap_points': 3, 'survey': True},
                {'type': 'solar_pv', 'sap_points': 4, 'survey': True, 'suitable': True}
            ],
            insulation_floor_area=162
        )

        roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)
        assert not roof_recommender.recommendations

        roof_recommender.recommend(phase=0)
        assert len(roof_recommender.recommendations) == 3

        # Should all be loft insulation recommendations
        assert all(
            rec["type"] == "loft_insulation" for rec in roof_recommender.recommendations
        )

    def test_no_access_pitched_roof_assumed(self):
        """
        In this case, the roof will have been surveyed as pitched, but the surveyor won't
        have gotten access to the property to check the insulation. Therefore, we
        recommend loft insulation. We assume that the roof is a locked off loft
        :return:
        """

        property_instance = Mock(
            id=0,
            roof={
                'original_description': 'Pitched, limited insulation (assumed)',
                'clean_description': 'Pitched, limited insulation', 'thermal_transmittance': None,
                'thermal_transmittance_unit': None, 'is_pitched': True, 'is_roof_room': False, 'is_loft': False,
                'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, 'is_assumed': True,
                'has_dwelling_above': False, 'is_valid': True, 'insulation_thickness': 'below average'
            },
            roof_area=73.24,
            data={"county": None, "local-authority-label": "Manchester"},
            already_installed=[],
            find_my_epc_components=[
                {'component_name': 'Wall', 'description': 'Solid brick, as built, no insulation (assumed)',
                 'efficiency': 'Very poor', 'appearance_index': 0},
                {'component_name': 'Wall', 'description': 'System built, as built, no insulation (assumed)',
                 'efficiency': 'Poor', 'appearance_index': 1},
                {'component_name': 'Wall', 'description': 'Cavity wall, filled cavity', 'efficiency': 'Average',
                 'appearance_index': 2},
                {'component_name': 'Roof', 'description': 'Pitched, limited insulation (assumed)',
                 'efficiency': 'Very poor', 'appearance_index': 0},
                {'component_name': 'Window', 'description': 'Fully double glazed', 'efficiency': 'Average',
                 'appearance_index': 0},
                {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas',
                 'efficiency': 'Good', 'appearance_index': 0},
                {'component_name': 'Main heating control', 'description': 'Programmer and room thermostat',
                 'efficiency': 'Average', 'appearance_index': 0},
                {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good',
                 'appearance_index': 0},
                {'component_name': 'Lighting', 'description': 'Low energy lighting in 75% of fixed outlets',
                 'efficiency': 'Very good', 'appearance_index': 0},
                {'component_name': 'Roof', 'description': '(another dwelling above)', 'efficiency': 'N/A',
                 'appearance_index': 1},
                {'component_name': 'Floor', 'description': 'Suspended, no insulation (assumed)', 'efficiency': 'N/A',
                 'appearance_index': 0},
                {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A',
                 'appearance_index': 1},
                {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A',
                 'appearance_index': 0}
            ],
            age_band="B",
            non_invasive_recommendations=[
                {'type': 'internal_wall_insulation', 'sap_points': 2, 'survey': True},
                {'type': 'suspended_floor_insulation', 'sap_points': 2, 'survey': True},
                {'type': 'solid_floor_insulation', 'sap_points': 1, 'survey': True},
                {'type': 'low_energy_lighting', 'sap_points': 0, 'survey': True}
            ],
            insulation_floor_area=60
        )

        roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)
        assert not roof_recommender.recommendations

        roof_recommender.recommend(phase=0)
        assert len(roof_recommender.recommendations) == 3

        # Should all be loft insulation recommendations
        assert all(
            rec["type"] == "loft_insulation" for rec in roof_recommender.recommendations
        )

    def test_traditional_loft_insulation(self):
        property_instance = Mock(
            id=0,
            roof={
                'original_description': 'Pitched, no insulation', 'clean_description': 'Pitched, no insulation',
                'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True,
                'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
                'is_at_rafters': False, 'is_assumed': False, 'has_dwelling_above': False, 'is_valid': True,
                'insulation_thickness': 'none'
            },
            roof_area=48.82666666666667,
            data={"county": None, "local-authority-label": "Manchester"},
            already_installed=[],
            find_my_epc_components=[
                {'component_name': 'Wall', 'description': 'Cavity wall, filled cavity', 'efficiency': 'Good',
                 'appearance_index': 0},
                {'component_name': 'Roof', 'description': 'Pitched, no insulation', 'efficiency': 'Very poor',
                 'appearance_index': 0},
                {'component_name': 'Window', 'description': 'Fully double glazed', 'efficiency': 'Good',
                 'appearance_index': 0},
                {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas',
                 'efficiency': 'Good', 'appearance_index': 0},
                {'component_name': 'Main heating control', 'description': 'TRVs and bypass', 'efficiency': 'Average',
                 'appearance_index': 0},
                {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good',
                 'appearance_index': 0},
                {'component_name': 'Lighting', 'description': 'Low energy lighting in all fixed outlets',
                 'efficiency': 'Very good', 'appearance_index': 0},
                {'component_name': 'Floor', 'description': 'Solid, no insulation (assumed)', 'efficiency': 'N/A',
                 'appearance_index': 0},
                {'component_name': 'Secondary heating', 'description': 'Room heaters, electric', 'efficiency': 'N/A',
                 'appearance_index': 0}
            ],
            age_band="F",
            non_invasive_recommendations=[
                {'type': 'loft_insulation', 'sap_points': 9, 'survey': True},
                {'type': 'solid_floor_insulation', 'sap_points': 2, 'survey': True},
                {'type': 'solar_water_heating', 'sap_points': 1, 'survey': True},
                {'type': 'solar_pv', 'sap_points': 11, 'survey': True, 'suitable': True}
            ],
            insulation_floor_area=40.0
        )

        roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)
        assert not roof_recommender.recommendations

        roof_recommender.recommend(0)
        assert len(roof_recommender.recommendations) == 3
        # should all be loft insulation recommendations
        assert all(rec["type"] == "loft_insulation" for rec in roof_recommender.recommendations)

    def sloping_ceiling_limited_insulation(self):
        property_instance = Mock(
            id=0,
            roof={
                "original_description": 'Pitched, limited insulation (assumed)',
                'clean_description': 'Pitched, limited insulation',
                'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_pitched': True,
                'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False,
                'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
                'insulation_thickness': 'below average'
            },
            roof_area=35,
            data={"county": None, "local-authority-label": "Manchester"},
            already_installed=[],
            find_my_epc_components=[
                {'component_name': 'Wall', 'description': 'Cavity wall, as built, no insulation (assumed)',
                 'efficiency': 'poor', 'appearance_index': 0},
                {'component_name': 'Roof', 'description': 'Pitched, limited insulation (assumed)',
                 'efficiency': 'Very poor', 'appearance_index': 0},
                {'component_name': 'Window', 'description': 'Fully double glazed', 'efficiency': 'Average',
                 'appearance_index': 0},
                {'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas',
                 'efficiency': 'Good', 'appearance_index': 0},
                {'component_name': 'Main heating control', 'description': 'TRVs and bypass',
                 'efficiency': 'Average', 'appearance_index': 0},
                {'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good',
                 'appearance_index': 0},
                {'component_name': 'Lighting', 'description': 'Low energy lighting in all fixed outlets',
                 'efficiency': 'Very good', 'appearance_index': 0},
                {'component_name': 'Floor', 'description': '(another dwelling below)', 'efficiency': 'N/A',
                 'appearance_index': 0},
                {'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A',
                 'appearance_index': 0}
            ],
            age_band="B",
            non_invasive_recommendations=[
                {'type': 'sloping_ceiling_insulation', 'sap_points': 2, 'survey': True},
                {'type': 'flat_roof_insulation', 'sap_points': 2, 'survey': True},
            ],
        )

        # We expect a sloping ceiling insulation recommendation
        roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)
        assert not roof_recommender.recommendations

        roof_recommender.recommend(phase=0)
        assert len(roof_recommender.recommendations) == 1
        assert roof_recommender.recommendations[0]["type"] == "sloping_ceiling_insulation"
        assert roof_recommender.recommendations[0]["measure_type"] == "sloping_ceiling_insulation"
        assert roof_recommender.recommendations[0]["description"] == \
               "Insulate sloping ceilings at the rafters and re-decorate"
        assert roof_recommender.recommendations[0]["simulation_config"] == {
            'roof_insulation_thickness_ending': 'average',
            'roof_thermal_transmittance_ending': 0.5,
            'roof_energy_eff_ending': 'Average'
        }
        assert roof_recommender.recommendations[0]["description_simulation"] == {
            'roof-description': 'Pitched, insulated', 'roof-energy-eff': 'Average'
        }
