import os
from datetime import date

import pytest

from backend.documents_parser.extractor import PasHubRdSapSiteNotesExtractor
from backend.documents_parser.pdf import pdf_to_text_list
from datatypes.epc.domain.epc_property_data import (
    EpcPropertyData,
    InstantaneousWwhrs,
    MainHeatingDetail,
    SapBuildingPart,
    SapEnergySource,
    SapFloorDimension,
    SapHeating,
    SapVentilation,
    SapWindow,
    ShowerOutlet,
    ShowerOutlets,
)
from datatypes.epc.domain.mapper import EpcPropertyDataMapper

PDF_PATH = os.path.join(os.path.dirname(__file__), "fixtures", "PasHubSiteNotes_1.pdf")
PDF_PATH_2 = os.path.join(
    os.path.dirname(__file__), "fixtures", "PasHubSiteNotes_2.pdf"
)


class TestPdfToEpcPropertyData:
    @pytest.fixture
    def result(self) -> EpcPropertyData:
        with open(PDF_PATH, "rb") as f:
            pdf_bytes = f.read()
        site_notes = PasHubRdSapSiteNotesExtractor(
            pdf_to_text_list(pdf_bytes)
        ).extract()
        return EpcPropertyDataMapper.from_site_notes(site_notes)

    def test_full_epc_property_data(self, result: EpcPropertyData) -> None:
        assert result == EpcPropertyData(
            dwelling_type="Mid-terrace house",
            inspection_date=date(2025, 9, 25),
            tenure="Rented Social",
            transaction_type="Grant-Scheme (ECO, RHI, etc.)",
            roofs=[],
            walls=[],
            floors=[],
            main_heating=[],
            door_count=2,
            sap_heating=SapHeating(
                instantaneous_wwhrs=InstantaneousWwhrs(),
                main_heating_details=[
                    MainHeatingDetail(
                        has_fghrs=False,
                        main_fuel_type="Mains gas",
                        heat_emitter_type="Radiators",
                        emitter_temperature="Unknown",
                        main_heating_control="Programmer, room thermostat and TRVs",
                        fan_flue_present=True,
                        condensing=True,
                        weather_compensator=False,
                        central_heating_pump_age_str="Unknown",
                    )
                ],
                has_fixed_air_conditioning=False,
                shower_outlets=ShowerOutlets(
                    shower_outlet=ShowerOutlet(
                        shower_outlet_type="Non-Electric Shower"
                    ),
                ),
            ),
            sap_windows=[
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North West",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=2.3,
                    window_height=1.2,
                    draught_proofed=True,
                    window_location="Main Building",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North West",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=1.0,
                    window_height=1.2,
                    draught_proofed=True,
                    window_location="Main Building",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North East",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=1.0,
                    window_height=0.9,
                    draught_proofed=True,
                    window_location="Main Building",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=1.0,
                    window_height=0.9,
                    draught_proofed=True,
                    window_location="Extension 1",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North East",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=1.7,
                    window_height=0.9,
                    draught_proofed=True,
                    window_location="Extension 1",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North West",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=2.3,
                    window_height=0.9,
                    draught_proofed=True,
                    window_location="Extension 1",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North West",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=1.2,
                    window_height=1.0,
                    draught_proofed=True,
                    window_location="Extension 1",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
                SapWindow(
                    frame_material="Wooden or PVC",
                    glazing_gap="16 mm or more",
                    orientation="North East",
                    window_type="Window",
                    glazing_type="Double glazing, Unknown install date",
                    window_width=1.0,
                    window_height=0.9,
                    draught_proofed=True,
                    window_location="Extension 1",
                    window_wall_type="External wall",
                    permanent_shutters_present=False,
                ),
            ],
            sap_energy_source=SapEnergySource(
                mains_gas=True,
                meter_type="Single",
                pv_battery_count=0,
                wind_turbines_count=0,
                gas_smart_meter_present=True,
                is_dwelling_export_capable=True,
                wind_turbines_terrain_type="Suburban",
                electricity_smart_meter_present=True,
            ),
            sap_building_parts=[
                SapBuildingPart(
                    identifier="main",
                    construction_age_band="1950-1966",
                    wall_construction="Cavity",
                    wall_insulation_type="Filled Cavity",
                    wall_thickness_measured=True,
                    party_wall_construction="Cavity Masonry, Filled",
                    sap_floor_dimensions=[
                        SapFloorDimension(
                            room_height_m=2.19,
                            total_floor_area_m2=35.68,
                            party_wall_length_m=10.62,
                            heat_loss_perimeter_m=13.44,
                            floor=1,
                        ),
                        SapFloorDimension(
                            room_height_m=2.17,
                            total_floor_area_m2=35.68,
                            party_wall_length_m=10.62,
                            heat_loss_perimeter_m=11.0,
                            floor=0,
                        ),
                    ],
                    wall_thickness_mm=310,
                    roof_insulation_location="Joists",
                    roof_insulation_thickness=100,
                    floor_type="Ground Floor",
                    floor_construction_type="Solid",
                    floor_insulation_type_str="As Built",
                    floor_u_value_known=False,
                ),
                SapBuildingPart(
                    identifier="extension_1",
                    construction_age_band="2003-2006",
                    wall_construction="Cavity",
                    wall_insulation_type="As built",
                    wall_thickness_measured=True,
                    party_wall_construction="Cavity Masonry, Filled",
                    sap_floor_dimensions=[
                        SapFloorDimension(
                            room_height_m=2.0,
                            total_floor_area_m2=3.8,
                            party_wall_length_m=0.0,
                            heat_loss_perimeter_m=5.7,
                            floor=0,
                        ),
                    ],
                    wall_thickness_mm=310,
                    roof_insulation_location="Sloping ceiling insulation",
                    roof_insulation_thickness="As built",
                ),
            ],
            solar_water_heating=False,
            has_hot_water_cylinder=False,
            has_fixed_air_conditioning=False,
            wet_rooms_count=0,
            extensions_count=1,
            heated_rooms_count=0,
            open_chimneys_count=0,
            habitable_rooms_count=3,
            insulated_door_count=0,
            cfl_fixed_lighting_bulbs_count=1,
            led_fixed_lighting_bulbs_count=0,
            incandescent_fixed_lighting_bulbs_count=4,
            total_floor_area_m2=75.16,
            built_form="Mid-terrace",
            property_type="House",
            has_conservatory=False,
            blocked_chimneys_count=0,
            draughtproofed_door_count=2,
            address_line_1="40, Abbey Place",
            post_town="Crewe",
            postcode="CW1 4JR",
            report_reference="6EA2A86D-94CE-4792-8D49-AB495C744EDD",
            number_of_storeys=2,
            any_unheated_rooms=False,
            waste_water_heat_recovery="None",
            hydro=False,
            photovoltaic_array=False,
            sap_ventilation=SapVentilation(
                ventilation_type="Mechanical Extract - Decentralised",
                draught_lobby=False,
                pressure_test="No test",
                open_flues_count=0,
                closed_flues_count=0,
                boiler_flues_count=0,
                other_flues_count=0,
                extract_fans_count=0,
                passive_vents_count=0,
                flueless_gas_fires_count=0,
                ventilation_in_pcdf_database=False,
            ),
        )


class TestPdfToEpcPropertyDataFixture2:
    @pytest.fixture
    def result(self) -> EpcPropertyData:
        with open(PDF_PATH_2, "rb") as f:
            pdf_bytes = f.read()
        site_notes = PasHubRdSapSiteNotesExtractor(
            pdf_to_text_list(pdf_bytes)
        ).extract()
        return EpcPropertyDataMapper.from_site_notes(site_notes)

    def test_cylinder_insulation_thickness(self, result: EpcPropertyData) -> None:
        assert result.sap_heating.cylinder_insulation_thickness_mm == 38

    def test_cylinder_size(self, result: EpcPropertyData) -> None:
        assert result.sap_heating.cylinder_size == "Normal (90-130 litres)"

    def test_secondary_heating_type(self, result: EpcPropertyData) -> None:
        assert result.sap_heating.secondary_heating_type == "Open fire in grate"


PDF_PATH_3 = os.path.join(
    os.path.dirname(__file__), "fixtures", "PasHubSiteNotes_3.pdf"
)


class TestPdfToEpcPropertyDataFixture3:
    @pytest.fixture
    def result(self) -> EpcPropertyData:
        with open(PDF_PATH_3, "rb") as f:
            pdf_bytes = f.read()
        site_notes = PasHubRdSapSiteNotesExtractor(
            pdf_to_text_list(pdf_bytes)
        ).extract()
        return EpcPropertyDataMapper.from_site_notes(site_notes)

    def test_immersion_heating_type(self, result: EpcPropertyData) -> None:
        assert result.sap_heating.immersion_heating_type == "Dual"

    def test_pv_connection(self, result: EpcPropertyData) -> None:
        assert (
            result.sap_energy_source.pv_connection
            == "Connected to dwellings electricity meter"
        )

    def test_photovoltaic_supply_percent_roof(self, result: EpcPropertyData) -> None:
        assert result.sap_energy_source.photovoltaic_supply is not None
        assert (
            result.sap_energy_source.photovoltaic_supply.none_or_no_details.percent_roof_area
            == 45
        )

    def test_electric_storage_heater_fuel_type(self, result: EpcPropertyData) -> None:
        assert (
            result.sap_heating.main_heating_details[0].main_fuel_type == "Electricity"
        )


PDF_PATH_4 = os.path.join(
    os.path.dirname(__file__), "fixtures", "PasHubSiteNotes_4.pdf"
)


class TestPdfToEpcPropertyDataFixture4:
    @pytest.fixture
    def result(self) -> EpcPropertyData:
        with open(PDF_PATH_4, "rb") as f:
            pdf_bytes = f.read()
        site_notes = PasHubRdSapSiteNotesExtractor(
            pdf_to_text_list(pdf_bytes)
        ).extract()
        return EpcPropertyDataMapper.from_site_notes(site_notes)

    def test_cylinder_insulation_type(self, result: EpcPropertyData) -> None:
        assert result.sap_heating.cylinder_insulation_type == "Factory fitted"

    def test_heat_pump_fuel_type(self, result: EpcPropertyData) -> None:
        assert (
            result.sap_heating.main_heating_details[0].main_fuel_type == "Electricity"
        )

    def test_roof_insulation_location_unknown(self, result: EpcPropertyData) -> None:
        assert result.sap_building_parts[0].roof_insulation_location == "Unknown"

    def test_roof_insulation_thickness_none(self, result: EpcPropertyData) -> None:
        assert result.sap_building_parts[0].roof_insulation_thickness is None


PDF_PATH_5 = os.path.join(
    os.path.dirname(__file__), "fixtures", "PasHubSiteNotes_5.pdf"
)


class TestPdfToEpcPropertyDataFixture5:
    @pytest.fixture
    def result(self) -> EpcPropertyData:
        with open(PDF_PATH_5, "rb") as f:
            pdf_bytes = f.read()
        site_notes = PasHubRdSapSiteNotesExtractor(
            pdf_to_text_list(pdf_bytes)
        ).extract()
        return EpcPropertyDataMapper.from_site_notes(site_notes)

    def test_cfl_bulb_count(self, result: EpcPropertyData) -> None:
        assert result.cfl_fixed_lighting_bulbs_count == 2

    def test_secondary_heating_type(self, result: EpcPropertyData) -> None:
        assert (
            result.sap_heating.secondary_heating_type
            == "Panel, convector or radiant heaters"
        )

    def test_electric_shower_outlet_type(self, result: EpcPropertyData) -> None:
        assert result.sap_heating.shower_outlets is not None
        assert (
            result.sap_heating.shower_outlets.shower_outlet.shower_outlet_type
            == "Electric Shower"
        )


PDF_PATH_6 = os.path.join(
    os.path.dirname(__file__), "fixtures", "PasHubSiteNotes_6.pdf"
)


class TestPdfToEpcPropertyDataFixture6:
    @pytest.fixture
    def result(self) -> EpcPropertyData:
        with open(PDF_PATH_6, "rb") as f:
            pdf_bytes = f.read()
        site_notes = PasHubRdSapSiteNotesExtractor(
            pdf_to_text_list(pdf_bytes)
        ).extract()
        return EpcPropertyDataMapper.from_site_notes(site_notes)

    def test_party_wall_construction(self, result: EpcPropertyData) -> None:
        assert (
            result.sap_building_parts[0].party_wall_construction
            == "Solid Masonry, Timber Frame, or System Built"
        )
