"""
MCP-Tool-Definitionen für Klima-Risiko-Bewertung.
6 Tools: Emissionen, Sektoren, Projektionen, Vergleiche, Trends, Risiko-Assessment.
"""

from datetime import datetime
from mcp.server.fastmcp import FastMCP
from src.clients.climate import (
    get_country_emissions,
    get_sector_emissions as fetch_sector_emissions,
    get_climate_projection as fetch_climate_projection,
    get_multiple_country_emissions,
    get_emission_history,
)


def register_tools(mcp: FastMCP) -> None:
    """Alle Klima-Tools beim MCP-Server registrieren."""

    @mcp.tool()
    async def get_emissions(
        country_code: str,
        year: int | None = None,
    ) -> str:
        """CO2-Emissionen eines Landes abrufen via Climate TRACE.

        Args:
            country_code: ISO 3166-1 alpha-3 Ländercode (z.B. DEU, USA, CHN, IND, GBR)
            year: Optionales Jahr (z.B. 2022). Ohne Angabe werden die neuesten Daten zurückgegeben.

        Returns:
            CO2-Emissionsdaten mit Gesamtwert und Aufschlüsselung nach Sektoren.
        """
        try:
            data = await get_country_emissions(country_code, year)

            if not data:
                return f"Keine Emissionsdaten fuer {country_code} gefunden."

            # Daten aufbereiten
            result_lines = [f"CO2-Emissionen fuer {country_code.upper()}"]
            if year:
                result_lines[0] += f" ({year})"
            result_lines.append("=" * 50)

            if isinstance(data, list):
                total_co2 = 0
                sector_data = []
                for entry in data:
                    emissions = entry.get("emissions", {})
                    co2_val = emissions.get("co2", 0) if isinstance(emissions, dict) else 0
                    sector = entry.get("sector", "Unbekannt")
                    total_co2 += co2_val
                    if co2_val > 0:
                        sector_data.append((sector, co2_val))

                # Gesamtemissionen in Tonnen -> Megatonnen
                total_mt = total_co2 / 1_000_000
                result_lines.append(f"Gesamt: {total_mt:,.2f} Mt CO2")
                result_lines.append("")

                # Top-Sektoren
                sector_data.sort(key=lambda x: x[1], reverse=True)
                result_lines.append("Aufschluesselung nach Sektor:")
                for sector, val in sector_data[:10]:
                    mt = val / 1_000_000
                    pct = (val / total_co2 * 100) if total_co2 > 0 else 0
                    result_lines.append(f"  {sector}: {mt:,.2f} Mt ({pct:.1f}%)")
            else:
                result_lines.append(f"Rohdaten: {str(data)[:500]}")

            return "\n".join(result_lines)

        except Exception as e:
            return f"Fehler beim Abruf der Emissionen fuer {country_code}: {str(e)}"

    @mcp.tool()
    async def get_sector_emissions_tool(
        country_code: str,
        sector: str,
        year: int | None = None,
    ) -> str:
        """Emissionen nach Sektor fuer ein Land abrufen.

        Args:
            country_code: ISO 3166-1 alpha-3 Ländercode (z.B. DEU, USA, CHN)
            sector: Sektor — power, transportation, manufacturing, agriculture,
                    buildings, fossil-fuel-operations, mineral-extraction, waste,
                    forestry-and-land-use
            year: Optionales Jahr fuer die Abfrage.

        Returns:
            Detaillierte Emissionsdaten fuer den gewaehlten Sektor.
        """
        valid_sectors = [
            "power", "transportation", "manufacturing", "agriculture",
            "buildings", "fossil-fuel-operations", "mineral-extraction",
            "waste", "forestry-and-land-use",
        ]

        sector_lower = sector.lower()
        if sector_lower not in valid_sectors:
            return (
                f"Unbekannter Sektor: {sector}.\n"
                f"Gueltige Sektoren: {', '.join(valid_sectors)}"
            )

        try:
            data = await fetch_sector_emissions(country_code, sector_lower, year)

            if not data:
                return f"Keine Daten fuer Sektor '{sector}' in {country_code}."

            result_lines = [
                f"Sektor-Emissionen: {sector.upper()} in {country_code.upper()}"
            ]
            if year:
                result_lines[0] += f" ({year})"
            result_lines.append("=" * 50)

            if isinstance(data, list):
                for entry in data:
                    emissions = entry.get("emissions", {})
                    co2_val = emissions.get("co2", 0) if isinstance(emissions, dict) else 0
                    subsector = entry.get("subsector", entry.get("sector", ""))
                    mt = co2_val / 1_000_000
                    result_lines.append(f"  {subsector}: {mt:,.2f} Mt CO2")
            else:
                result_lines.append(f"Daten: {str(data)[:500]}")

            return "\n".join(result_lines)

        except Exception as e:
            return f"Fehler: {str(e)}"

    @mcp.tool()
    async def get_climate_projection(
        lat: float,
        lon: float,
        scenario: str = "rcp45",
        start_year: int = 2025,
        end_year: int = 2050,
    ) -> str:
        """Klimaprojektionen fuer einen Standort abrufen (Temperatur & Niederschlag).

        Args:
            lat: Breitengrad (z.B. 52.52 fuer Berlin)
            lon: Laengengrad (z.B. 13.405 fuer Berlin)
            scenario: Klimaszenario — rcp26 (optimistisch), rcp45 (moderat),
                      rcp85 (pessimistisch), oder CMIP6: ssp126, ssp245, ssp370, ssp585
            start_year: Startjahr der Projektion (Standard: 2025)
            end_year: Endjahr der Projektion (Standard: 2050)

        Returns:
            Temperatur- und Niederschlagsprojektionen als Jahresdurchschnitte.
        """
        try:
            data = await fetch_climate_projection(
                lat, lon, scenario, start_year, end_year
            )

            result_lines = [
                f"Klimaprojektion ({scenario.upper()}) fuer {lat}, {lon}",
                f"Zeitraum: {start_year} - {end_year}",
                "=" * 50,
            ]

            # Tägliche Daten zu Jahresdurchschnitten aggregieren
            daily = data.get("daily", {})
            times = daily.get("time", [])

            # Alle möglichen Schlüssel für die Modellvariablen suchen
            temp_max_key = None
            temp_min_key = None
            precip_key = None

            for key in daily:
                if "temperature_2m_max" in key and key != "time":
                    temp_max_key = key
                elif "temperature_2m_min" in key and key != "time":
                    temp_min_key = key
                elif "precipitation_sum" in key and key != "time":
                    precip_key = key

            temp_max = daily.get(temp_max_key, []) if temp_max_key else []
            temp_min = daily.get(temp_min_key, []) if temp_min_key else []
            precip = daily.get(precip_key, []) if precip_key else []

            if not times:
                result_lines.append("Keine Projektionsdaten verfuegbar.")
                return "\n".join(result_lines)

            # Nach Jahren gruppieren
            yearly_data: dict[int, dict] = {}
            for i, date_str in enumerate(times):
                yr = int(date_str[:4])
                if yr not in yearly_data:
                    yearly_data[yr] = {"temp_max": [], "temp_min": [], "precip": []}
                if i < len(temp_max) and temp_max[i] is not None:
                    yearly_data[yr]["temp_max"].append(temp_max[i])
                if i < len(temp_min) and temp_min[i] is not None:
                    yearly_data[yr]["temp_min"].append(temp_min[i])
                if i < len(precip) and precip[i] is not None:
                    yearly_data[yr]["precip"].append(precip[i])

            result_lines.append(
                f"{'Jahr':<6} {'Temp Max':>10} {'Temp Min':>10} {'Niederschlag':>14}"
            )
            result_lines.append("-" * 44)

            # Jedes 5. Jahr anzeigen fuer Uebersichtlichkeit
            years_sorted = sorted(yearly_data.keys())
            display_years = [y for y in years_sorted if y % 5 == 0 or y == years_sorted[0] or y == years_sorted[-1]]

            for yr in display_years:
                yd = yearly_data[yr]
                avg_max = sum(yd["temp_max"]) / len(yd["temp_max"]) if yd["temp_max"] else 0
                avg_min = sum(yd["temp_min"]) / len(yd["temp_min"]) if yd["temp_min"] else 0
                total_precip = sum(yd["precip"]) if yd["precip"] else 0
                result_lines.append(
                    f"{yr:<6} {avg_max:>9.1f}C {avg_min:>9.1f}C {total_precip:>11.0f} mm"
                )

            # Temperaturtrend berechnen
            if len(years_sorted) >= 2:
                first_yr = years_sorted[0]
                last_yr = years_sorted[-1]
                yd_first = yearly_data[first_yr]
                yd_last = yearly_data[last_yr]

                if yd_first["temp_max"] and yd_last["temp_max"]:
                    avg_first = (
                        sum(yd_first["temp_max"]) / len(yd_first["temp_max"])
                        + sum(yd_first["temp_min"]) / len(yd_first["temp_min"])
                    ) / 2
                    avg_last = (
                        sum(yd_last["temp_max"]) / len(yd_last["temp_max"])
                        + sum(yd_last["temp_min"]) / len(yd_last["temp_min"])
                    ) / 2
                    delta = avg_last - avg_first
                    result_lines.append("")
                    result_lines.append(
                        f"Temperaturtrend: {'+' if delta > 0 else ''}{delta:.1f}C "
                        f"({first_yr}-{last_yr})"
                    )

            return "\n".join(result_lines)

        except ValueError as e:
            return str(e)
        except Exception as e:
            return f"Fehler bei Klimaprojektion: {str(e)}"

    @mcp.tool()
    async def compare_countries(
        country_codes: list[str],
        metric: str = "co2",
        year: int | None = None,
    ) -> str:
        """CO2-Emissionen mehrerer Laender vergleichen.

        Args:
            country_codes: Liste von ISO alpha-3 Laendercodes (z.B. ["DEU", "USA", "CHN"])
            metric: Vergleichsmetrik — co2 (Standard), co2_per_sector
            year: Optionales Jahr fuer den Vergleich

        Returns:
            Vergleichstabelle der Emissionen sortiert nach Hoehe.
        """
        if len(country_codes) < 2:
            return "Mindestens 2 Laendercodes fuer einen Vergleich noetig."
        if len(country_codes) > 10:
            return "Maximal 10 Laender gleichzeitig vergleichbar."

        try:
            data = await get_multiple_country_emissions(country_codes, year)

            result_lines = [
                f"Laendervergleich: CO2-Emissionen",
            ]
            if year:
                result_lines[0] += f" ({year})"
            result_lines.append("=" * 50)

            # Pro Land aggregieren
            country_totals: dict[str, float] = {}

            if isinstance(data, list):
                for entry in data:
                    country = entry.get("country", "???")
                    emissions = entry.get("emissions", {})
                    co2_val = emissions.get("co2", 0) if isinstance(emissions, dict) else 0
                    country_totals[country] = country_totals.get(country, 0) + co2_val

            # Nach Emissionen sortieren
            sorted_countries = sorted(
                country_totals.items(), key=lambda x: x[1], reverse=True
            )

            result_lines.append(f"{'Land':<8} {'CO2 (Mt)':>12} {'Anteil':>10}")
            result_lines.append("-" * 32)

            total_all = sum(v for _, v in sorted_countries) or 1

            for country, co2_val in sorted_countries:
                mt = co2_val / 1_000_000
                pct = co2_val / total_all * 100
                result_lines.append(f"{country:<8} {mt:>11,.2f} {pct:>9.1f}%")

            if not sorted_countries:
                result_lines.append("Keine Daten fuer die angegebenen Laender gefunden.")

            return "\n".join(result_lines)

        except Exception as e:
            return f"Fehler beim Laendervergleich: {str(e)}"

    @mcp.tool()
    async def get_emission_trends(
        country_code: str,
        years: int = 10,
    ) -> str:
        """Historische Emissionstrends eines Landes ueber mehrere Jahre.

        Args:
            country_code: ISO 3166-1 alpha-3 Laendercode (z.B. DEU, USA, CHN)
            years: Anzahl Jahre zurueckblickend (Standard: 10, Max: 30)

        Returns:
            Zeitreihe der jaehrlichen CO2-Emissionen mit Trendanalyse.
        """
        years = min(years, 30)
        current_year = datetime.now().year
        start_year = current_year - years
        end_year = current_year

        try:
            data = await get_emission_history(country_code, start_year, end_year)

            result_lines = [
                f"Emissionstrend: {country_code.upper()} ({start_year}-{end_year})",
                "=" * 50,
            ]

            # Nach Jahr aggregieren
            yearly_emissions: dict[int, float] = {}

            if isinstance(data, list):
                for entry in data:
                    emissions = entry.get("emissions", {})
                    co2_val = emissions.get("co2", 0) if isinstance(emissions, dict) else 0
                    # Jahr aus den Daten extrahieren
                    entry_year = entry.get("year", None)
                    if entry_year:
                        yearly_emissions[entry_year] = (
                            yearly_emissions.get(entry_year, 0) + co2_val
                        )

            if not yearly_emissions:
                result_lines.append("Keine historischen Daten verfuegbar.")
                return "\n".join(result_lines)

            sorted_years = sorted(yearly_emissions.keys())

            result_lines.append(f"{'Jahr':<6} {'CO2 (Mt)':>12} {'Veraenderung':>14}")
            result_lines.append("-" * 34)

            prev_val = None
            for yr in sorted_years:
                mt = yearly_emissions[yr] / 1_000_000
                if prev_val is not None and prev_val > 0:
                    change_pct = (yearly_emissions[yr] - prev_val) / prev_val * 100
                    change_str = f"{'+' if change_pct > 0 else ''}{change_pct:.1f}%"
                else:
                    change_str = "—"
                result_lines.append(f"{yr:<6} {mt:>11,.2f} {change_str:>14}")
                prev_val = yearly_emissions[yr]

            # Gesamttrend
            if len(sorted_years) >= 2:
                first_val = yearly_emissions[sorted_years[0]]
                last_val = yearly_emissions[sorted_years[-1]]
                if first_val > 0:
                    total_change = (last_val - first_val) / first_val * 100
                    result_lines.append("")
                    result_lines.append(
                        f"Gesamttrend: {'+' if total_change > 0 else ''}"
                        f"{total_change:.1f}% "
                        f"({sorted_years[0]}-{sorted_years[-1]})"
                    )
                    if total_change < -10:
                        result_lines.append("Bewertung: Signifikante Reduktion")
                    elif total_change < 0:
                        result_lines.append("Bewertung: Leichte Reduktion")
                    elif total_change < 10:
                        result_lines.append("Bewertung: Stagnation")
                    else:
                        result_lines.append("Bewertung: Anstieg — Massnahmen noetig")

            return "\n".join(result_lines)

        except Exception as e:
            return f"Fehler bei Trendabfrage: {str(e)}"

    @mcp.tool()
    async def assess_climate_risk(
        lat: float,
        lon: float,
        location_name: str = "",
    ) -> str:
        """Einfache Klimarisiko-Bewertung fuer einen Standort.

        Analysiert Temperatur- und Niederschlagsprojektionen und bewertet
        Risiken fuer Hitze, Ueberflutung und Duerre.

        Args:
            lat: Breitengrad (z.B. 52.52 fuer Berlin, 48.14 fuer Muenchen)
            lon: Laengengrad (z.B. 13.405 fuer Berlin, 11.58 fuer Muenchen)
            location_name: Optionaler Name des Standorts fuer die Anzeige

        Returns:
            Risikobewertung mit Indikatoren fuer Hitze, Ueberflutung und Duerre.
        """
        location_label = location_name or f"{lat}, {lon}"

        try:
            # Projektion im moderaten Szenario (RCP4.5) abrufen
            data = await fetch_climate_projection(
                lat, lon, scenario="rcp45", start_year=2025, end_year=2060
            )

            result_lines = [
                f"Klimarisiko-Assessment: {location_label}",
                f"Szenario: RCP 4.5 (moderat), 2025-2060",
                "=" * 50,
            ]

            daily = data.get("daily", {})
            times = daily.get("time", [])

            # Dynamische Schlüssel finden
            temp_max_key = None
            temp_min_key = None
            precip_key = None

            for key in daily:
                if "temperature_2m_max" in key and key != "time":
                    temp_max_key = key
                elif "temperature_2m_min" in key and key != "time":
                    temp_min_key = key
                elif "precipitation_sum" in key and key != "time":
                    precip_key = key

            temp_max = daily.get(temp_max_key, []) if temp_max_key else []
            temp_min = daily.get(temp_min_key, []) if temp_min_key else []
            precip = daily.get(precip_key, []) if precip_key else []

            if not times:
                result_lines.append("Keine Projektionsdaten verfuegbar.")
                return "\n".join(result_lines)

            # Zeiträume vergleichen: 2025-2035 vs. 2050-2060
            early: dict = {"temp_max": [], "temp_min": [], "precip": [], "hot_days": 0, "dry_days": 0, "heavy_rain": 0}
            late: dict = {"temp_max": [], "temp_min": [], "precip": [], "hot_days": 0, "dry_days": 0, "heavy_rain": 0}

            for i, date_str in enumerate(times):
                yr = int(date_str[:4])

                tmax = temp_max[i] if i < len(temp_max) and temp_max[i] is not None else None
                tmin = temp_min[i] if i < len(temp_min) and temp_min[i] is not None else None
                prcp = precip[i] if i < len(precip) and precip[i] is not None else None

                target = None
                if 2025 <= yr <= 2035:
                    target = early
                elif 2050 <= yr <= 2060:
                    target = late

                if target is not None:
                    if tmax is not None:
                        target["temp_max"].append(tmax)
                        if tmax > 35:
                            target["hot_days"] += 1
                    if tmin is not None:
                        target["temp_min"].append(tmin)
                    if prcp is not None:
                        target["precip"].append(prcp)
                        if prcp < 0.1:
                            target["dry_days"] += 1
                        if prcp > 30:
                            target["heavy_rain"] += 1

            # Durchschnitte berechnen
            def avg(lst: list) -> float:
                return sum(lst) / len(lst) if lst else 0

            early_avg_temp = (avg(early["temp_max"]) + avg(early["temp_min"])) / 2
            late_avg_temp = (avg(late["temp_max"]) + avg(late["temp_min"])) / 2
            temp_increase = late_avg_temp - early_avg_temp

            early_avg_precip = sum(early["precip"])
            late_avg_precip = sum(late["precip"])

            # Normalisieren auf Jahreszeiträume
            early_years = 11  # 2025-2035
            late_years = 11   # 2050-2060

            early_hot_per_year = early["hot_days"] / early_years
            late_hot_per_year = late["hot_days"] / late_years
            early_dry_per_year = early["dry_days"] / early_years
            late_dry_per_year = late["dry_days"] / late_years
            early_heavy_per_year = early["heavy_rain"] / early_years
            late_heavy_per_year = late["heavy_rain"] / late_years

            # ─── Risikobewertung ─────────────────────────────
            result_lines.append("")
            result_lines.append("TEMPERATUR")
            result_lines.append(f"  Durchschnitt 2025-2035: {early_avg_temp:.1f}C")
            result_lines.append(f"  Durchschnitt 2050-2060: {late_avg_temp:.1f}C")
            result_lines.append(f"  Erwaermung: +{temp_increase:.1f}C")
            result_lines.append("")

            # Hitzerisiko
            heat_risk = "NIEDRIG"
            if late_hot_per_year > 30:
                heat_risk = "SEHR HOCH"
            elif late_hot_per_year > 15:
                heat_risk = "HOCH"
            elif late_hot_per_year > 5:
                heat_risk = "MITTEL"

            result_lines.append("HITZERISIKO: " + heat_risk)
            result_lines.append(f"  Hitzetage (>35C): {early_hot_per_year:.0f}/Jahr -> {late_hot_per_year:.0f}/Jahr")

            # Ueberflutungsrisiko
            flood_risk = "NIEDRIG"
            if late_heavy_per_year > 20:
                flood_risk = "SEHR HOCH"
            elif late_heavy_per_year > 10:
                flood_risk = "HOCH"
            elif late_heavy_per_year > 5:
                flood_risk = "MITTEL"

            result_lines.append("")
            result_lines.append("UEBERFLUTUNGSRISIKO: " + flood_risk)
            result_lines.append(f"  Starkregen (>30mm): {early_heavy_per_year:.0f}/Jahr -> {late_heavy_per_year:.0f}/Jahr")

            # Duerrerisiko
            drought_risk = "NIEDRIG"
            if late_dry_per_year > 200:
                drought_risk = "SEHR HOCH"
            elif late_dry_per_year > 150:
                drought_risk = "HOCH"
            elif late_dry_per_year > 100:
                drought_risk = "MITTEL"

            result_lines.append("")
            result_lines.append("DUERRERISIKO: " + drought_risk)
            result_lines.append(f"  Trockentage (<0.1mm): {early_dry_per_year:.0f}/Jahr -> {late_dry_per_year:.0f}/Jahr")

            # Gesamtrisiko
            risk_scores = {"NIEDRIG": 1, "MITTEL": 2, "HOCH": 3, "SEHR HOCH": 4}
            overall_score = max(
                risk_scores[heat_risk],
                risk_scores[flood_risk],
                risk_scores[drought_risk],
            )
            overall_labels = {1: "NIEDRIG", 2: "MITTEL", 3: "HOCH", 4: "SEHR HOCH"}

            result_lines.append("")
            result_lines.append("=" * 50)
            result_lines.append(f"GESAMTRISIKO: {overall_labels[overall_score]}")
            result_lines.append("")
            result_lines.append(
                "Hinweis: Vereinfachte Bewertung basierend auf Klimaprojektionen. "
                "Fuer detaillierte Analysen lokale Faktoren (Topographie, "
                "Infrastruktur, Kuestennaehe) beruecksichtigen."
            )

            return "\n".join(result_lines)

        except Exception as e:
            return f"Fehler bei Risikobewertung: {str(e)}"
