"""Map a Landlord-Override main-heating-system value to a heating Simulation Overlay. A main-heating-system value is one canonical system archetype ("Gas boiler, combi", "Electric storage heaters, fan"). The calculator reads the primary system's `sap_main_heating_code` (SAP Table 4a/4b), so the overlay maps the archetype to a representative code and emits a whole-dwelling `HeatingOverlay` targeting `main_heating_details[0]` (`building_part` is ignored). It composes field-wise with the main_fuel / water_heating overlays. The SEDBUK A-G efficiency band the Hyde "Heating" column carries is NOT honoured yet (no efficiency slot on the overlay/MainHeatingDetail) -- archetypes map to their modern/condensing Table 4b code, so an old low-rated boiler is currently modelled at the condensing efficiency. Heat pumps and community heating (which resolve via main_heating_index_number / community codes, not a Table 4b code) are left UNKNOWN until modelled. Unresolvable values produce no overlay. """ from __future__ import annotations from typing import Optional from domain.modelling.simulation import EpcSimulation, HeatingOverlay # Canonical system archetype → representative `sap_main_heating_code` (SAP Table # 4b boiler rows / Table 4a). Codes map to the modern/condensing variant (A-G # efficiency deferred): 102 regular condensing, 104 condensing combi, 120 CPSU, # 404 fan storage heaters, 191 direct-acting electric boiler. _MAIN_HEATING_CODES: dict[str, int] = { "Gas boiler, combi": 104, "Gas boiler, regular": 102, "Gas CPSU": 120, "Electric storage heaters, old": 401, "Electric storage heaters, slimline": 402, "Electric storage heaters, convector": 403, "Electric storage heaters, fan": 404, "Direct-acting electric": 191, } def main_heating_overlay_for( main_heating_value: str, building_part: int ) -> Optional[EpcSimulation]: code = _MAIN_HEATING_CODES.get(main_heating_value) if code is None: return None return EpcSimulation(heating=HeatingOverlay(sap_main_heating_code=code))