from dataclasses import dataclass
from pathlib import Path
from typing import ClassVar

import matplotlib.pyplot as plt
import pandas as pd

from .base import SimStadtResults, detect_decimal
from .kpi import KPI
from .providers import Providers


@dataclass(repr=False)
class HeatDemandResults(SimStadtResults):
    """Results for Heat Demand (and Heat+Cool Demand) workflows."""

    MAX_FLAT_ROOF_DIFFERENCE = 0.1  # [m]
    TOTAL_DEMAND = "Total Yearly Heating + DHW demand"

    supported_providers: ClassVar[list[str]] = [
        Providers.HEAT_DEMAND,
        Providers.HEAT_DEMAND_WITH_SHADOW,
        Providers.HEAT_DEMAND_WITH_REFURBISHMENT,
        Providers.HEAT_DEMAND_WITH_HISTORIC_REFURBISHMENT,
    ]
    csv_identifier = "DIN18599"

    def _parse_results(self) -> pd.DataFrame:
        csv_decimal = detect_decimal(self.csv_path, 5, "Latitude")
        df = pd.read_csv(self.csv_path, skiprows=list(range(19)) + [20], sep=";", decimal=csv_decimal)
        df["has_flat_roof"] = (
            df["Ridge/mean Height"] - df["Eaves/mean Height"] < self.MAX_FLAT_ROOF_DIFFERENCE
        ).fillna(False)
        df.attrs["Heating"] = "Yearly Heating demand" in df.columns
        df.attrs["Cooling"] = "Yearly Cooling demand" in df.columns
        return df

    @property
    def kpis(self) -> list[KPI]:
        df = self.dataframe
        custom_kpis = [KPI("Number of buildings", df.shape[0], precision=0)]
        sums = [("Heated area", "m²"), ("Footprint area", "m²")]

        if df.attrs["Heating"]:
            specific_heat_demand = df[self.TOTAL_DEMAND].sum() / df["Heated area"].sum()
            heated_buildings = int((df[self.TOTAL_DEMAND] > 10_000).sum())
            custom_kpis.extend(
                [
                    KPI("Number of heated buildings", heated_buildings, precision=0),
                    KPI("Specific Heating Demand", specific_heat_demand, "kWh / (m² · a)", precision=0),
                ]
            )
            sums.extend(
                [
                    ("Yearly Heating demand", "kWh / a"),
                    (self.TOTAL_DEMAND, "kWh / a"),
                ]
            )

        if df.attrs["Cooling"]:
            specific_cooling_demand = df["Yearly Cooling demand"].sum() / df["Heated area"].sum()
            custom_kpis.append(KPI("Specific Cooling Demand", specific_cooling_demand, "kWh / (m² · a)", precision=0))
            sums.append(("Yearly Cooling demand", "kWh / a"))

        averages = [("Mean Uvalue", "W / (m² · K)", 1), ("Year of construction", None), ("Storey number", None)]
        return custom_kpis + self._prepare_kpis(sums, averages)

    @property
    def diagrams(self) -> dict[str, Path]:
        heat_png = self.workflow_path / "heating.png"
        ax = self.monthly_df().plot.bar(
            rot=0,
            ylabel="[MWh]",
            width=0.8,
            color={"Monthly Heating Demand": "darkred", "Monthly Cooling Demand": "darkblue"},
        )
        plt.savefig(heat_png, bbox_inches="tight", dpi=300)
        plt.close(ax.figure)
        return {"Monthly demands": heat_png}

    def monthly_df(self) -> pd.DataFrame:
        months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
        df = self.dataframe
        monthly_df = pd.DataFrame([], index=pd.Index(months))
        for mode in ["Heating", "Cooling"]:
            search_str = f"{mode} demand"
            found_cols = [
                col for col in df.columns if search_str in col and "Yearly" not in col and "Specific" not in col
            ]
            if found_cols:
                monthly_df[f"Monthly {mode} Demand"] = (df[found_cols].sum() / 1000).values
        return monthly_df
