from __future__ import annotations

from typing import Optional
from sqlmodel import SQLModel, Field

from datatypes.epc.domain.epc_property_data import (
    EpcPropertyData,
    EnergyElement,
    MainHeatingDetail,
    SapBuildingPart,
    SapFloorDimension,
    SapFlatDetails,
    SapWindow,
)


class EpcPropertyModel(SQLModel, table=True):
    __tablename__ = "epc_property"

    id: Optional[int] = Field(default=None, primary_key=True)
    property_id: Optional[int] = Field(default=None)
    portfolio_id: Optional[int] = Field(default=None)
    uploaded_file_id: Optional[int] = Field(default=None)

    # Identity / admin
    uprn: Optional[int] = Field(default=None)
    uprn_source: Optional[str] = Field(default=None)
    report_reference: Optional[str] = Field(default=None)
    report_type: Optional[str] = Field(default=None)
    assessment_type: Optional[str] = Field(default=None)
    sap_version: Optional[float] = Field(default=None)
    schema_type: Optional[str] = Field(default=None)
    schema_versions_original: Optional[str] = Field(default=None)
    status: Optional[str] = Field(default=None)
    calculation_software_version: Optional[str] = Field(default=None)

    # Address
    address_line_1: Optional[str] = Field(default=None)
    address_line_2: Optional[str] = Field(default=None)
    post_town: Optional[str] = Field(default=None)
    postcode: Optional[str] = Field(default=None)
    region_code: Optional[str] = Field(default=None)
    country_code: Optional[str] = Field(default=None)
    language_code: Optional[str] = Field(default=None)

    # Property description
    dwelling_type: str
    property_type: Optional[str] = Field(default=None)
    built_form: Optional[str] = Field(default=None)
    tenure: str
    transaction_type: str
    inspection_date: str  # store as ISO string; cast on read if needed
    completion_date: Optional[str] = Field(default=None)
    registration_date: Optional[str] = Field(default=None)
    total_floor_area_m2: float
    measurement_type: Optional[int] = Field(default=None)

    # Flags
    solar_water_heating: bool
    has_hot_water_cylinder: bool
    has_fixed_air_conditioning: bool
    has_conservatory: Optional[bool] = Field(default=None)
    has_heated_separate_conservatory: Optional[bool] = Field(default=None)
    conservatory_type: Optional[int] = Field(default=None)

    # Counts
    door_count: int
    wet_rooms_count: int
    extensions_count: int
    heated_rooms_count: int
    open_chimneys_count: int
    habitable_rooms_count: int
    insulated_door_count: int
    cfl_fixed_lighting_bulbs_count: int
    led_fixed_lighting_bulbs_count: int
    incandescent_fixed_lighting_bulbs_count: int
    blocked_chimneys_count: Optional[int] = Field(default=None)
    draughtproofed_door_count: Optional[int] = Field(default=None)
    energy_rating_average: Optional[int] = Field(default=None)
    low_energy_fixed_lighting_bulbs_count: Optional[int] = Field(default=None)
    fixed_lighting_outlets_count: Optional[int] = Field(default=None)
    low_energy_fixed_lighting_outlets_count: Optional[int] = Field(default=None)
    number_of_storeys: Optional[int] = Field(default=None)
    any_unheated_rooms: Optional[bool] = Field(default=None)

    # Misc
    hydro: Optional[bool] = Field(default=None)
    photovoltaic_array: Optional[bool] = Field(default=None)
    waste_water_heat_recovery: Optional[str] = Field(default=None)
    pressure_test: Optional[int] = Field(default=None)
    pressure_test_certificate_number: Optional[int] = Field(default=None)
    percent_draughtproofed: Optional[int] = Field(default=None)
    insulated_door_u_value: Optional[float] = Field(default=None)
    multiple_glazed_proportion: Optional[int] = Field(default=None)
    windows_transmission_u_value: Optional[float] = Field(default=None)
    windows_transmission_data_source: Optional[int] = Field(default=None)
    windows_transmission_solar_transmittance: Optional[float] = Field(default=None)

    # Energy source
    energy_mains_gas: bool
    energy_meter_type: str
    energy_pv_battery_count: int
    energy_wind_turbines_count: int
    energy_gas_smart_meter_present: bool
    energy_is_dwelling_export_capable: bool
    energy_wind_turbines_terrain_type: str
    energy_electricity_smart_meter_present: bool
    energy_pv_connection: Optional[str] = Field(default=None)
    energy_pv_percent_roof_area: Optional[int] = Field(default=None)
    energy_pv_battery_capacity: Optional[float] = Field(default=None)
    energy_wind_turbine_hub_height: Optional[float] = Field(default=None)
    energy_wind_turbine_rotor_diameter: Optional[float] = Field(default=None)

    # Heating config
    heating_cylinder_size: Optional[str] = Field(default=None)
    heating_water_heating_code: Optional[int] = Field(default=None)
    heating_water_heating_fuel: Optional[int] = Field(default=None)
    heating_immersion_heating_type: Optional[str] = Field(default=None)
    heating_cylinder_insulation_type: Optional[str] = Field(default=None)
    heating_cylinder_thermostat: Optional[str] = Field(default=None)
    heating_secondary_fuel_type: Optional[int] = Field(default=None)
    heating_secondary_heating_type: Optional[str] = Field(default=None)
    heating_cylinder_insulation_thickness_mm: Optional[int] = Field(default=None)
    heating_wwhrs_index_number_1: Optional[int] = Field(default=None)
    heating_wwhrs_index_number_2: Optional[int] = Field(default=None)
    heating_shower_outlet_type: Optional[str] = Field(default=None)
    heating_shower_wwhrs: Optional[int] = Field(default=None)

    # Ventilation
    ventilation_type: Optional[str] = Field(default=None)
    ventilation_draught_lobby: Optional[bool] = Field(default=None)
    ventilation_pressure_test: Optional[str] = Field(default=None)
    ventilation_open_flues_count: Optional[int] = Field(default=None)
    ventilation_closed_flues_count: Optional[int] = Field(default=None)
    ventilation_boiler_flues_count: Optional[int] = Field(default=None)
    ventilation_other_flues_count: Optional[int] = Field(default=None)
    ventilation_extract_fans_count: Optional[int] = Field(default=None)
    ventilation_passive_vents_count: Optional[int] = Field(default=None)
    ventilation_flueless_gas_fires_count: Optional[int] = Field(default=None)
    ventilation_in_pcdf_database: Optional[bool] = Field(default=None)
    mechanical_ventilation: Optional[int] = Field(default=None)
    mechanical_vent_duct_type: Optional[int] = Field(default=None)
    mechanical_vent_duct_placement: Optional[int] = Field(default=None)
    mechanical_vent_duct_insulation: Optional[int] = Field(default=None)
    mechanical_ventilation_index_number: Optional[int] = Field(default=None)
    mechanical_vent_measured_installation: Optional[str] = Field(default=None)

    @classmethod
    def from_epc_property_data(
        cls,
        data: EpcPropertyData,
        property_id: Optional[int] = None,
        portfolio_id: Optional[int] = None,
    ) -> EpcPropertyModel:
        es = data.sap_energy_source
        h = data.sap_heating
        v = data.sap_ventilation
        shower = h.shower_outlets.shower_outlet if h.shower_outlets else None
        pv = es.photovoltaic_supply
        wt = es.wind_turbine_details
        pvb = es.pv_batteries

        return cls(
            property_id=property_id,
            portfolio_id=portfolio_id,
            uprn=data.uprn,
            uprn_source=data.uprn_source,
            report_reference=data.report_reference,
            report_type=data.report_type,
            assessment_type=data.assessment_type,
            sap_version=data.sap_version,
            schema_type=data.schema_type,
            schema_versions_original=data.schema_versions_original,
            status=data.status,
            calculation_software_version=data.calculation_software_version,
            address_line_1=data.address_line_1,
            address_line_2=data.address_line_2,
            post_town=data.post_town,
            postcode=data.postcode,
            region_code=data.region_code,
            country_code=data.country_code,
            language_code=data.language_code,
            dwelling_type=data.dwelling_type,
            property_type=data.property_type,
            built_form=data.built_form,
            tenure=data.tenure,
            transaction_type=data.transaction_type,
            inspection_date=data.inspection_date.isoformat(),
            completion_date=(
                data.completion_date.isoformat() if data.completion_date else None
            ),
            registration_date=(
                data.registration_date.isoformat() if data.registration_date else None
            ),
            total_floor_area_m2=data.total_floor_area_m2,
            measurement_type=data.measurement_type,
            solar_water_heating=data.solar_water_heating,
            has_hot_water_cylinder=data.has_hot_water_cylinder,
            has_fixed_air_conditioning=data.has_fixed_air_conditioning,
            has_conservatory=data.has_conservatory,
            has_heated_separate_conservatory=data.has_heated_separate_conservatory,
            conservatory_type=data.conservatory_type,
            door_count=data.door_count,
            wet_rooms_count=data.wet_rooms_count,
            extensions_count=data.extensions_count,
            heated_rooms_count=data.heated_rooms_count,
            open_chimneys_count=data.open_chimneys_count,
            habitable_rooms_count=data.habitable_rooms_count,
            insulated_door_count=data.insulated_door_count,
            cfl_fixed_lighting_bulbs_count=data.cfl_fixed_lighting_bulbs_count,
            led_fixed_lighting_bulbs_count=data.led_fixed_lighting_bulbs_count,
            incandescent_fixed_lighting_bulbs_count=data.incandescent_fixed_lighting_bulbs_count,
            blocked_chimneys_count=data.blocked_chimneys_count,
            draughtproofed_door_count=data.draughtproofed_door_count,
            energy_rating_average=data.energy_rating_average,
            low_energy_fixed_lighting_bulbs_count=data.low_energy_fixed_lighting_bulbs_count,
            fixed_lighting_outlets_count=data.fixed_lighting_outlets_count,
            low_energy_fixed_lighting_outlets_count=data.low_energy_fixed_lighting_outlets_count,
            number_of_storeys=data.number_of_storeys,
            any_unheated_rooms=data.any_unheated_rooms,
            hydro=data.hydro,
            photovoltaic_array=data.photovoltaic_array,
            waste_water_heat_recovery=data.waste_water_heat_recovery,
            pressure_test=data.pressure_test,
            pressure_test_certificate_number=data.pressure_test_certificate_number,
            percent_draughtproofed=data.percent_draughtproofed,
            insulated_door_u_value=data.insulated_door_u_value,
            multiple_glazed_proportion=data.multiple_glazed_propertion,
            windows_transmission_u_value=(
                data.windows_transmission_details.u_value
                if data.windows_transmission_details
                else None
            ),
            windows_transmission_data_source=(
                data.windows_transmission_details.data_source
                if data.windows_transmission_details
                else None
            ),
            windows_transmission_solar_transmittance=(
                data.windows_transmission_details.solar_transmittance
                if data.windows_transmission_details
                else None
            ),
            energy_mains_gas=es.mains_gas,
            energy_meter_type=str(es.meter_type),
            energy_pv_battery_count=es.pv_battery_count,
            energy_wind_turbines_count=es.wind_turbines_count,
            energy_gas_smart_meter_present=es.gas_smart_meter_present,
            energy_is_dwelling_export_capable=es.is_dwelling_export_capable,
            energy_wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
            energy_electricity_smart_meter_present=es.electricity_smart_meter_present,
            energy_pv_connection=(
                str(es.pv_connection) if es.pv_connection is not None else None
            ),
            energy_pv_percent_roof_area=(
                pv.none_or_no_details.percent_roof_area if pv else None
            ),
            energy_pv_battery_capacity=pvb.pv_battery.battery_capacity if pvb else None,
            energy_wind_turbine_hub_height=wt.hub_height if wt else None,
            energy_wind_turbine_rotor_diameter=wt.rotor_diameter if wt else None,
            heating_cylinder_size=(
                str(h.cylinder_size) if h.cylinder_size is not None else None
            ),
            heating_water_heating_code=h.water_heating_code,
            heating_water_heating_fuel=h.water_heating_fuel,
            heating_immersion_heating_type=(
                str(h.immersion_heating_type)
                if h.immersion_heating_type is not None
                else None
            ),
            heating_cylinder_insulation_type=(
                str(h.cylinder_insulation_type)
                if h.cylinder_insulation_type is not None
                else None
            ),
            heating_cylinder_thermostat=h.cylinder_thermostat,
            heating_secondary_fuel_type=h.secondary_fuel_type,
            heating_secondary_heating_type=(
                str(h.secondary_heating_type)
                if h.secondary_heating_type is not None
                else None
            ),
            heating_cylinder_insulation_thickness_mm=h.cylinder_insulation_thickness_mm,
            heating_wwhrs_index_number_1=h.instantaneous_wwhrs.wwhrs_index_number1,
            heating_wwhrs_index_number_2=h.instantaneous_wwhrs.wwhrs_index_number2,
            heating_shower_outlet_type=(
                str(shower.shower_outlet_type) if shower else None
            ),
            heating_shower_wwhrs=shower.shower_wwhrs if shower else None,
            ventilation_type=v.ventilation_type if v else None,
            ventilation_draught_lobby=v.draught_lobby if v else None,
            ventilation_pressure_test=v.pressure_test if v else None,
            ventilation_open_flues_count=v.open_flues_count if v else None,
            ventilation_closed_flues_count=v.closed_flues_count if v else None,
            ventilation_boiler_flues_count=v.boiler_flues_count if v else None,
            ventilation_other_flues_count=v.other_flues_count if v else None,
            ventilation_extract_fans_count=v.extract_fans_count if v else None,
            ventilation_passive_vents_count=v.passive_vents_count if v else None,
            ventilation_flueless_gas_fires_count=(
                v.flueless_gas_fires_count if v else None
            ),
            ventilation_in_pcdf_database=v.ventilation_in_pcdf_database if v else None,
            mechanical_ventilation=data.mechanical_ventilation,
            mechanical_vent_duct_type=data.mechanical_vent_duct_type,
            mechanical_vent_duct_placement=data.mechanical_vent_duct_placement,
            mechanical_vent_duct_insulation=data.mechanical_vent_duct_insulation,
            mechanical_ventilation_index_number=data.mechanical_ventilation_index_number,
            mechanical_vent_measured_installation=data.mechanical_vent_measured_installation,
        )


class EpcPropertyEnergyPerformanceModel(SQLModel, table=True):
    __tablename__ = "epc_property_energy_performance"

    id: Optional[int] = Field(default=None, primary_key=True)
    epc_property_id: int = Field(
        foreign_key="epc_property.id", nullable=False, unique=True
    )

    energy_rating_current: Optional[int] = Field(default=None)
    energy_consumption_current: Optional[int] = Field(default=None)
    environmental_impact_current: Optional[int] = Field(default=None)
    heating_cost_current: Optional[float] = Field(default=None)
    lighting_cost_current: Optional[float] = Field(default=None)
    hot_water_cost_current: Optional[float] = Field(default=None)
    co2_emissions_current: Optional[float] = Field(default=None)
    co2_emissions_current_per_floor_area: Optional[int] = Field(default=None)
    current_energy_efficiency_band: Optional[str] = Field(default=None)
    energy_rating_potential: Optional[float] = Field(default=None)
    energy_consumption_potential: Optional[int] = Field(default=None)
    environmental_impact_potential: Optional[int] = Field(default=None)
    heating_cost_potential: Optional[float] = Field(default=None)
    lighting_cost_potential: Optional[float] = Field(default=None)
    hot_water_cost_potential: Optional[float] = Field(default=None)
    co2_emissions_potential: Optional[float] = Field(default=None)
    potential_energy_efficiency_band: Optional[str] = Field(default=None)

    @classmethod
    def from_epc_property_data(
        cls, data: EpcPropertyData, epc_property_id: int
    ) -> EpcPropertyEnergyPerformanceModel:
        return cls(
            epc_property_id=epc_property_id,
            energy_rating_current=data.energy_rating_current,
            energy_consumption_current=data.energy_consumption_current,
            environmental_impact_current=data.environmental_impact_current,
            heating_cost_current=data.heating_cost_current,
            lighting_cost_current=data.lighting_cost_current,
            hot_water_cost_current=data.hot_water_cost_current,
            co2_emissions_current=data.co2_emissions_current,
            co2_emissions_current_per_floor_area=data.co2_emissions_current_per_floor_area,
            current_energy_efficiency_band=(
                data.current_energy_efficiency_band.value
                if data.current_energy_efficiency_band
                else None
            ),
            energy_rating_potential=data.energy_rating_potential,
            energy_consumption_potential=data.energy_consumption_potential,
            environmental_impact_potential=data.environmental_impact_potential,
            heating_cost_potential=data.heating_cost_potential,
            lighting_cost_potential=data.lighting_cost_potential,
            hot_water_cost_potential=data.hot_water_cost_potential,
            co2_emissions_potential=data.co2_emissions_potential,
            potential_energy_efficiency_band=(
                data.potential_energy_efficiency_band.value
                if data.potential_energy_efficiency_band
                else None
            ),
        )


class EpcFlatDetailsModel(SQLModel, table=True):
    __tablename__ = "epc_flat_details"

    id: Optional[int] = Field(default=None, primary_key=True)
    epc_property_id: int = Field(
        foreign_key="epc_property.id", nullable=False, unique=True
    )

    level: int
    top_storey: str
    flat_location: int
    heat_loss_corridor: int
    storey_count: Optional[int] = Field(default=None)
    unheated_corridor_length_m: Optional[int] = Field(default=None)

    @classmethod
    def from_domain(
        cls, flat: SapFlatDetails, epc_property_id: int
    ) -> EpcFlatDetailsModel:
        return cls(
            epc_property_id=epc_property_id,
            level=flat.level,
            top_storey=flat.top_storey,
            flat_location=flat.flat_location,
            heat_loss_corridor=flat.heat_loss_corridor,
            storey_count=flat.storey_count,
            unheated_corridor_length_m=flat.unheated_corridor_length_m,
        )


class EpcMainHeatingDetailModel(SQLModel, table=True):
    __tablename__ = "epc_main_heating_detail"

    id: Optional[int] = Field(default=None, primary_key=True)
    epc_property_id: int = Field(foreign_key="epc_property.id", nullable=False)

    has_fghrs: bool
    main_fuel_type: str
    heat_emitter_type: str
    emitter_temperature: str
    main_heating_control: str
    fan_flue_present: Optional[bool] = Field(default=None)
    boiler_flue_type: Optional[int] = Field(default=None)
    boiler_ignition_type: Optional[int] = Field(default=None)
    central_heating_pump_age: Optional[int] = Field(default=None)
    central_heating_pump_age_str: Optional[str] = Field(default=None)
    main_heating_index_number: Optional[int] = Field(default=None)
    sap_main_heating_code: Optional[int] = Field(default=None)
    main_heating_number: Optional[int] = Field(default=None)
    main_heating_category: Optional[int] = Field(default=None)
    main_heating_fraction: Optional[int] = Field(default=None)
    main_heating_data_source: Optional[int] = Field(default=None)
    condensing: Optional[bool] = Field(default=None)
    weather_compensator: Optional[bool] = Field(default=None)

    @classmethod
    def from_domain(
        cls, detail: MainHeatingDetail, epc_property_id: int
    ) -> EpcMainHeatingDetailModel:
        return cls(
            epc_property_id=epc_property_id,
            has_fghrs=detail.has_fghrs,
            main_fuel_type=str(detail.main_fuel_type),
            heat_emitter_type=str(detail.heat_emitter_type),
            emitter_temperature=str(detail.emitter_temperature),
            main_heating_control=str(detail.main_heating_control),
            fan_flue_present=detail.fan_flue_present,
            boiler_flue_type=detail.boiler_flue_type,
            boiler_ignition_type=detail.boiler_ignition_type,
            central_heating_pump_age=detail.central_heating_pump_age,
            central_heating_pump_age_str=detail.central_heating_pump_age_str,
            main_heating_index_number=detail.main_heating_index_number,
            sap_main_heating_code=detail.sap_main_heating_code,
            main_heating_number=detail.main_heating_number,
            main_heating_category=detail.main_heating_category,
            main_heating_fraction=detail.main_heating_fraction,
            main_heating_data_source=detail.main_heating_data_source,
            condensing=detail.condensing,
            weather_compensator=detail.weather_compensator,
        )


class EpcBuildingPartModel(SQLModel, table=True):
    __tablename__ = "epc_building_part"

    id: Optional[int] = Field(default=None, primary_key=True)
    epc_property_id: int = Field(foreign_key="epc_property.id", nullable=False)

    identifier: str
    construction_age_band: str
    wall_construction: str
    wall_insulation_type: str
    wall_thickness_measured: bool
    party_wall_construction: str
    building_part_number: Optional[int] = Field(default=None)
    wall_dry_lined: Optional[bool] = Field(default=None)
    wall_thickness_mm: Optional[int] = Field(default=None)
    wall_insulation_thickness: Optional[str] = Field(default=None)
    floor_heat_loss: Optional[int] = Field(default=None)
    floor_insulation_thickness: Optional[str] = Field(default=None)
    flat_roof_insulation_thickness: Optional[str] = Field(default=None)
    floor_type: Optional[str] = Field(default=None)
    floor_construction_type: Optional[str] = Field(default=None)
    floor_insulation_type_str: Optional[str] = Field(default=None)
    floor_u_value_known: Optional[bool] = Field(default=None)
    roof_construction: Optional[int] = Field(default=None)
    roof_insulation_location: Optional[str] = Field(default=None)
    roof_insulation_thickness: Optional[str] = Field(default=None)
    room_in_roof_floor_area: Optional[float] = Field(default=None)
    room_in_roof_construction_age_band: Optional[str] = Field(default=None)
    alt_wall_1_area: Optional[float] = Field(default=None)
    alt_wall_1_dry_lined: Optional[str] = Field(default=None)
    alt_wall_1_construction: Optional[int] = Field(default=None)
    alt_wall_1_insulation_type: Optional[int] = Field(default=None)
    alt_wall_1_thickness_measured: Optional[str] = Field(default=None)
    alt_wall_1_insulation_thickness: Optional[str] = Field(default=None)
    alt_wall_2_area: Optional[float] = Field(default=None)
    alt_wall_2_dry_lined: Optional[str] = Field(default=None)
    alt_wall_2_construction: Optional[int] = Field(default=None)
    alt_wall_2_insulation_type: Optional[int] = Field(default=None)
    alt_wall_2_thickness_measured: Optional[str] = Field(default=None)
    alt_wall_2_insulation_thickness: Optional[str] = Field(default=None)

    @classmethod
    def from_domain(
        cls, part: SapBuildingPart, epc_property_id: int
    ) -> EpcBuildingPartModel:
        rir = part.sap_room_in_roof
        aw1 = part.sap_alternative_wall_1
        aw2 = part.sap_alternative_wall_2
        return cls(
            epc_property_id=epc_property_id,
            identifier=part.identifier,
            construction_age_band=part.construction_age_band,
            wall_construction=str(part.wall_construction),
            wall_insulation_type=str(part.wall_insulation_type),
            wall_thickness_measured=part.wall_thickness_measured,
            party_wall_construction=str(part.party_wall_construction),
            building_part_number=part.building_part_number,
            wall_dry_lined=part.wall_dry_lined,
            wall_thickness_mm=part.wall_thickness_mm,
            wall_insulation_thickness=part.wall_insulation_thickness,
            floor_heat_loss=part.floor_heat_loss,
            floor_insulation_thickness=part.floor_insulation_thickness,
            flat_roof_insulation_thickness=(
                str(part.flat_roof_insulation_thickness)
                if part.flat_roof_insulation_thickness is not None
                else None
            ),
            floor_type=part.floor_type,
            floor_construction_type=part.floor_construction_type,
            floor_insulation_type_str=part.floor_insulation_type_str,
            floor_u_value_known=part.floor_u_value_known,
            roof_construction=part.roof_construction,
            roof_insulation_location=(
                str(part.roof_insulation_location)
                if part.roof_insulation_location is not None
                else None
            ),
            roof_insulation_thickness=(
                str(part.roof_insulation_thickness)
                if part.roof_insulation_thickness is not None
                else None
            ),
            room_in_roof_floor_area=float(rir.floor_area) if rir else None,
            room_in_roof_construction_age_band=(
                rir.construction_age_band if rir else None
            ),
            alt_wall_1_area=aw1.wall_area if aw1 else None,
            alt_wall_1_dry_lined=aw1.wall_dry_lined if aw1 else None,
            alt_wall_1_construction=aw1.wall_construction if aw1 else None,
            alt_wall_1_insulation_type=aw1.wall_insulation_type if aw1 else None,
            alt_wall_1_thickness_measured=aw1.wall_thickness_measured if aw1 else None,
            alt_wall_1_insulation_thickness=(
                aw1.wall_insulation_thickness if aw1 else None
            ),
            alt_wall_2_area=aw2.wall_area if aw2 else None,
            alt_wall_2_dry_lined=aw2.wall_dry_lined if aw2 else None,
            alt_wall_2_construction=aw2.wall_construction if aw2 else None,
            alt_wall_2_insulation_type=aw2.wall_insulation_type if aw2 else None,
            alt_wall_2_thickness_measured=aw2.wall_thickness_measured if aw2 else None,
            alt_wall_2_insulation_thickness=(
                aw2.wall_insulation_thickness if aw2 else None
            ),
        )


class EpcFloorDimensionModel(SQLModel, table=True):
    __tablename__ = "epc_floor_dimension"

    id: Optional[int] = Field(default=None, primary_key=True)
    epc_building_part_id: int = Field(
        foreign_key="epc_building_part.id", nullable=False
    )

    floor: Optional[int] = Field(default=None)
    room_height_m: float
    total_floor_area_m2: float
    party_wall_length_m: float
    heat_loss_perimeter_m: float
    floor_insulation: Optional[int] = Field(default=None)
    floor_construction: Optional[int] = Field(default=None)

    @classmethod
    def from_domain(
        cls, dim: SapFloorDimension, epc_building_part_id: int
    ) -> EpcFloorDimensionModel:
        return cls(
            epc_building_part_id=epc_building_part_id,
            floor=dim.floor,
            room_height_m=dim.room_height_m,
            total_floor_area_m2=dim.total_floor_area_m2,
            party_wall_length_m=dim.party_wall_length_m,
            heat_loss_perimeter_m=dim.heat_loss_perimeter_m,
            floor_insulation=dim.floor_insulation,
            floor_construction=dim.floor_construction,
        )


class EpcWindowModel(SQLModel, table=True):
    __tablename__ = "epc_window"

    id: Optional[int] = Field(default=None, primary_key=True)
    epc_property_id: int = Field(foreign_key="epc_property.id", nullable=False)

    frame_material: Optional[str] = Field(default=None)
    glazing_gap: str
    orientation: str
    window_type: str
    glazing_type: str
    window_width: float
    window_height: float
    draught_proofed: bool
    window_location: str
    window_wall_type: str
    permanent_shutters_present: bool
    frame_factor: Optional[float] = Field(default=None)
    permanent_shutters_insulated: Optional[str] = Field(default=None)
    transmission_u_value: Optional[float] = Field(default=None)
    transmission_data_source: Optional[str] = Field(default=None)
    transmission_solar_transmittance: Optional[float] = Field(default=None)

    @classmethod
    def from_domain(cls, window: SapWindow, epc_property_id: int) -> EpcWindowModel:
        td = window.window_transmission_details
        return cls(
            epc_property_id=epc_property_id,
            frame_material=window.frame_material,
            glazing_gap=str(window.glazing_gap),
            orientation=str(window.orientation),
            window_type=str(window.window_type),
            glazing_type=str(window.glazing_type),
            window_width=window.window_width,
            window_height=window.window_height,
            draught_proofed=bool(window.draught_proofed),
            window_location=str(window.window_location),
            window_wall_type=str(window.window_wall_type),
            permanent_shutters_present=bool(window.permanent_shutters_present),
            frame_factor=window.frame_factor,
            permanent_shutters_insulated=window.permanent_shutters_insulated,
            transmission_u_value=td.u_value if td else None,
            transmission_data_source=td.data_source if td else None,
            transmission_solar_transmittance=td.solar_transmittance if td else None,
        )


class EpcEnergyElementModel(SQLModel, table=True):
    __tablename__ = "epc_energy_element"

    id: Optional[int] = Field(default=None, primary_key=True)
    epc_property_id: int = Field(foreign_key="epc_property.id", nullable=False)

    element_type: str  # roof | wall | floor | main_heating | window | lighting | hot_water | secondary_heating | main_heating_controls
    description: str
    energy_efficiency_rating: int
    environmental_efficiency_rating: int

    @classmethod
    def from_domain(
        cls, element: EnergyElement, element_type: str, epc_property_id: int
    ) -> EpcEnergyElementModel:
        return cls(
            epc_property_id=epc_property_id,
            element_type=element_type,
            description=element.description,
            energy_efficiency_rating=element.energy_efficiency_rating,
            environmental_efficiency_rating=element.environmental_efficiency_rating,
        )
