"""The lighting Recommendation Generator (LED upgrade). Detects a dwelling's non-LED fixed-lighting bulbs and emits one "Lighting" Recommendation whose single Option converts **every** bulb to LED (ADR-0023). SAP 10.2 RdSAP §12-1 rates lamp efficacy LED > low-energy-unknown > CFL > incandescent, so converting every non-LED type — incandescent, CFL, and the "low energy, type unknown" (LEL) bulbs alike — strictly improves the Appendix L lighting energy (worksheet line (232)). Unlike the fabric generators this is a **whole-dwelling** Measure: its overlay writes the four top-level bulb counts directly (`led = total`, the rest 0). It is a free Optimiser candidate — an LED upgrade improves SAP at low cost, so the Optimiser keeps or leaves it for least-cost-to-target (contrast ventilation's forced dependency). Detection + pricing only; impact is produced later by scoring (ADR-0016). """ from typing import Final, Optional from datatypes.epc.domain.epc_property_data import EpcPropertyData from domain.modelling.measure_type import MeasureType from domain.modelling.recommendation import Cost, MeasureOption, Recommendation from domain.modelling.simulation import EpcSimulation, LightingOverlay from repositories.product.product_repository import ProductRepository _LIGHTING_MEASURE_TYPE: Final[MeasureType] = MeasureType.LOW_ENERGY_LIGHTING def recommend_lighting( epc: EpcPropertyData, products: ProductRepository ) -> Optional[Recommendation]: """Return a lighting Recommendation upgrading every non-LED bulb to LED — its single Option — else None when the dwelling has no non-LED bulbs (already all-LED, or no bulb counts lodged).""" led: int = epc.led_fixed_lighting_bulbs_count or 0 cfl: int = epc.cfl_fixed_lighting_bulbs_count or 0 incandescent: int = epc.incandescent_fixed_lighting_bulbs_count or 0 low_energy: int = epc.low_energy_fixed_lighting_bulbs_count or 0 non_led: int = cfl + incandescent + low_energy if non_led == 0: return None product = products.get(_LIGHTING_MEASURE_TYPE) overlay = EpcSimulation( lighting=LightingOverlay( led_fixed_lighting_bulbs_count=led + non_led, cfl_fixed_lighting_bulbs_count=0, incandescent_fixed_lighting_bulbs_count=0, low_energy_fixed_lighting_bulbs_count=0, ) ) cost = Cost( total=non_led * product.unit_cost_per_m2, contingency_rate=product.contingency_rate, ) option = MeasureOption( measure_type=_LIGHTING_MEASURE_TYPE, description="Replace all non-LED bulbs with LED", overlay=overlay, cost=cost, material_id=product.id, ) return Recommendation(surface="Lighting", options=(option,))