from backend.Property import Property
from recommendations.Costs import Costs
from recommendations.recommendation_utils import override_costs, check_simulation_difference, check_use_survey
from etl.epc_clean.epc_attributes.HotWaterAttributes import HotWaterAttributes


class HotwaterRecommendations:
    def __init__(self, property_instance: Property):
        self.property = property_instance
        self.costs = Costs(self.property)

        self.recommendations = []

    def recommend(self, phase):
        """
        There are maybe a number of recommendations that are simultaneously applicable to the property.
        If this is true then the phase may need to be incrememnted from within this recommendation

        :param phase:
        :return:
        """
        # Reset the recommendations
        recommendations_phase = phase

        self.recommendations = []
        non_invasive_recommendations = self.property.non_invasive_recommendations
        if non_invasive_recommendations:
            measures = [
                r["type"] for r in non_invasive_recommendations if
                r["type"] in ["hot_water_tank_insulation", "cylinder_thermostat"]
            ]

            for m in measures:
                non_invasive_rec = [
                    r for r in non_invasive_recommendations if r["type"] == m
                ][0]
                if m == "hot_water_tank_insulation":
                    # We need to be able to stack these recommendations
                    self.recommend_tank_insulation(
                        phase=recommendations_phase,
                        sap_points=non_invasive_rec["sap_points"],
                        survey=check_use_survey(non_invasive_rec, self.property.epc_record.has_been_remodelled),
                    )

                    recommendations_phase += 1
                elif m == "cylinder_thermostat":
                    self.recommend_cylinder_thermostat(
                        phase=recommendations_phase,
                        sap_points=non_invasive_rec["sap_points"],
                        survey=check_use_survey(non_invasive_rec, self.property.epc_record.has_been_remodelled),
                    )
                    recommendations_phase += 1

        # This first iteration of the recommender will provide very basic recommendation
        # We recommend heating controls based on the main heating system

        if self.property.hotwater["clean_description"] == "Gas boiler/circulator, no cylinder thermostat":
            # Handle this case specifically:
            self.recommend_cylinder_thermostat_gas_boiler_circulator(phase=recommendations_phase)
            return

            # If there is no system present, but access to the mains, we

        has_tank_recommendation = [r for r in self.recommendations if r["type"] == "hot_water_tank_insulation"]

        if (
            (self.property.hotwater["heater_type"] in ["electric immersion"]) &
            (self.property.epc_record.hot_water_energy_eff == "Very Poor") &
            (self.property.hotwater["no_system_present"] is None) &
            (len(has_tank_recommendation) == 0)
        ):
            self.recommend_tank_insulation(phase=recommendations_phase)
            return

        has_cylinder_recommendation = [r for r in self.recommendations if r["type"] == "cylinder_thermostat"]

        if ((self.property.hotwater["clean_description"] == "From main system, no cylinder thermostat") &
            (len(has_cylinder_recommendation) == 0)):
            self.recommend_cylinder_thermostat(phase=recommendations_phase)
            return

    def recommend_tank_insulation(self, phase, sap_points=None, survey=False, _return=False):
        """
        If the home has a very poor hot water system, this is often indicative of a lack of insulation on the hot water
        tank. This is a very simple and cost effective improvement that can be made to the home. It will likely
        take the efficiency from very poor to poor.
        """

        recommendation_cost = self.costs.hot_water_tank_insulation()

        already_installed = "hot_water_tank_insulation" in self.property.already_installed
        if already_installed:
            recommendation_cost = override_costs(recommendation_cost)
            description = "Insulation tank has already been insulated, no further action required"
        else:
            description = "Insulate hot water tank"

        to_append = {
            "phase": phase,
            "parts": [],
            "type": "hot_water_tank_insulation",
            "measure_type": "hot_water_tank_insulation",
            "description": description,
            "starting_u_value": None,
            "new_u_value": None,
            "sap_points": sap_points,
            "already_installed": already_installed,
            **recommendation_cost,
            "simulation_config": {"hot_water_energy_eff_ending": "Poor"},
            "description_simulation": {
                "hot-water-energy-eff": "Poor"
            },
            "survey": survey,
            "innovation_rate": 0
        }
        if _return:
            return to_append

        self.recommendations.append(to_append)
        return

    def recommend_cylinder_thermostat(self, phase, sap_points=None, survey=False, _return=False):
        """
        If the home has a very poor hot water system, this is often indicative of a lack of insulation on the hot water
        tank. This is a very simple and cost effective improvement that can be made to the home.
        """

        recommendation_cost = self.costs.cylinder_thermostat()

        already_installed = "cylinder_thermostat" in self.property.already_installed
        if already_installed:
            recommendation_cost = override_costs(recommendation_cost)
            description = "Cylinder thermostat has already been installed, no further action required"
        else:
            description = "Install a smart cylinder thermostat on the hot water tank"

        new_epc_description = "From main system"
        hotwater_ending_config = HotWaterAttributes(new_epc_description).process()
        hotwater_simulation_config = check_simulation_difference(
            new_config=hotwater_ending_config, old_config=self.property.hotwater
        )

        simulation_config = {
            "hot_water_energy_eff_ending": self.property.epc_record.hot_water_energy_eff,
            **hotwater_simulation_config
        }

        to_append = {
            "phase": phase,
            "parts": [],
            "type": "cylinder_thermostat",
            "measure_type": "cylinder_thermostat",
            "description": description,
            "starting_u_value": None,
            "new_u_value": None,
            "sap_points": sap_points,
            "already_installed": already_installed,
            **recommendation_cost,
            "simulation_config": simulation_config,
            "description_simulation": {
                "hot-water-energy-eff": self.property.epc_record.hot_water_energy_eff,
                "hotwater-description": new_epc_description,
            },
            "survey": survey,
            "innovation_rate": 0
        }
        if _return:
            return to_append

        self.recommendations.append(to_append)
        return

    def recommend_cylinder_thermostat_gas_boiler_circulator(self, phase):
        """
        If the home has a very poor hot water system, this is often indicative of a lack of insulation on the
        hot water
        tank. This is a very simple and cost effective improvement that can be made to the home.
        """

        thermostat_recommendation_cost = self.costs.cylinder_thermostat()
        cylinder_recommendation_cost = self.costs.hot_water_tank_insulation()
        # Add them
        total_cost = {
            k: thermostat_recommendation_cost[k] + cylinder_recommendation_cost[k] for k in
            thermostat_recommendation_cost.keys()
        }

        already_installed = "cylinder_thermostat" in self.property.already_installed
        if already_installed:
            total_cost = override_costs(total_cost)
            description = "Cylinder thermostat & insulation has already been installed, no further action required"
        else:
            description = "Install a smart cylinder thermostat and insulate the hot water tank with 80mm insulation"

        new_epc_description = "From main system"
        hotwater_ending_config = HotWaterAttributes(new_epc_description).process()
        hotwater_simulation_config = check_simulation_difference(
            new_config=hotwater_ending_config, old_config=self.property.hotwater
        )

        if self.property.epc_record.hot_water_energy_eff in ["Very Poor", "Poor", "Average"]:
            new_efficiency = "Good"
        else:
            new_efficiency = self.property.epc_record.hot_water_energy_eff

        simulation_config = {
            "hot_water_energy_eff_ending": new_efficiency,
            **hotwater_simulation_config
        }

        to_append = {
            "phase": phase,
            "parts": [],
            "type": "cylinder_thermostat",
            "measure_type": "cylinder_thermostat",
            "description": description,
            "starting_u_value": None,
            "new_u_value": None,
            "sap_points": None,
            "already_installed": already_installed,
            **total_cost,
            "simulation_config": simulation_config,
            "description_simulation": {
                "hot-water-energy-eff": simulation_config["hot_water_energy_eff_ending"],
                "hotwater-description": new_epc_description,
            },
            "survey": False,
            "innovation_rate": 0
        }

        self.recommendations.append(to_append)
        return
