"""
Gemeinschafts-Bericht Generator
Erzeugt einen einseitigen PDF-Bericht über die EEG-Periode.
"""

import io
import os
from datetime import datetime

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    Image, HRFlowable, KeepTogether
)


# ─── Farben ────────────────────────────────────────────────────────────────
C_GREEN_DARK  = colors.HexColor('#1b5e20')
C_GREEN       = colors.HexColor('#2e7d32')
C_GREEN_MID   = colors.HexColor('#388e3c')
C_GREEN_LIGHT = colors.HexColor('#e8f5e9')
C_GREEN_PALE  = colors.HexColor('#f1f8e9')
C_BLUE_DARK   = colors.HexColor('#0d47a1')
C_BLUE        = colors.HexColor('#1565c0')
C_BLUE_LIGHT  = colors.HexColor('#e3f2fd')
C_BLUE_PALE   = colors.HexColor('#f0f7ff')
C_ORANGE      = colors.HexColor('#e65100')
C_ORANGE_LIGHT= colors.HexColor('#fff3e0')
C_GRAY_DARK   = colors.HexColor('#37474f')
C_GRAY        = colors.HexColor('#546e7a')
C_GRAY_MID    = colors.HexColor('#90a4ae')
C_GRAY_LIGHT  = colors.HexColor('#eceff1')
C_WHITE       = colors.white
C_BLACK       = colors.HexColor('#212121')
C_ROW_ALT     = colors.HexColor('#f9fbe7')


def _make_typday_chart(hourly_cons, hourly_gen, width_px=680, height_px=240) -> bytes:
    """Erzeugt die Typtagkurve als PNG-Bytes."""
    hours = list(range(24))
    cons  = [c if c is not None else 0.0 for c in hourly_cons]
    gen   = [g if g is not None else 0.0 for g in hourly_gen]
    cons_a = np.array(cons)
    gen_a  = np.array(gen)

    dpi = 120
    fig, ax = plt.subplots(figsize=(width_px / dpi, height_px / dpi), dpi=dpi)
    fig.patch.set_facecolor('white')
    ax.set_facecolor('#fafafa')

    # Eigendeckung (Overlap) – grün gefüllt
    ax.fill_between(hours, 0, np.minimum(cons_a, gen_a),
                    color='#43a047', alpha=0.35, label='Eigendeckung', zorder=2)
    # Netzbezug (Verbrauch > Erzeugung) – blau gefüllt
    ax.fill_between(hours, np.minimum(cons_a, gen_a), cons_a,
                    where=cons_a > gen_a,
                    color='#1565c0', alpha=0.25, label='Netzbezug', zorder=2)
    # Überschuss (Erzeugung > Verbrauch) – hellgrün gefüllt
    ax.fill_between(hours, np.minimum(cons_a, gen_a), gen_a,
                    where=gen_a > cons_a,
                    color='#66bb6a', alpha=0.30, label='Überschuss', zorder=2)

    # Linien
    ax.plot(hours, cons, color='#1565c0', linewidth=2.0, label='Ø Verbrauch (kW)', zorder=3)
    ax.plot(hours, gen,  color='#2e7d32', linewidth=2.0, label='Ø Erzeugung (kW)', zorder=3)

    ax.set_xlim(0, 23)
    ax.set_ylim(bottom=0)
    ax.set_xticks(range(0, 24, 2))
    ax.set_xticklabels([f'{h}:00' for h in range(0, 24, 2)], fontsize=7.5)
    ax.set_ylabel('kW', fontsize=8)
    ax.tick_params(axis='y', labelsize=7.5)
    ax.grid(True, color='#e0e0e0', linewidth=0.6, zorder=1)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)

    ax.legend(fontsize=7.5, loc='upper right', framealpha=0.85,
              ncol=2, handlelength=1.4, handletextpad=0.5)

    fig.tight_layout(pad=0.5)

    buf = io.BytesIO()
    fig.savefig(buf, format='png', dpi=dpi, bbox_inches='tight')
    plt.close(fig)
    buf.seek(0)
    return buf.read()


def generate_community_report(system, output_path: str) -> str:
    """Erzeugt einen einseitigen Gemeinschaftsbericht als PDF.

    Parameters
    ----------
    system      : Abrechnungssystem-Instanz nach prepare()
    output_path : Ziel-Pfad für die PDF-Datei

    Returns
    -------
    output_path (zur Bestätigung)
    """
    # ── Daten aus system ────────────────────────────────────────────────────
    eeg_name    = str(system.config.get('Vereinsname', 'Energiegemeinschaft')).strip()
    today       = datetime.now().strftime('%d.%m.%Y')

    evq = system.total_eigendeckung / system.total_erzeugung_tf * 100 \
          if system.total_erzeugung_tf else None
    aut = system.total_eigendeckung / system.total_gesamtverbrauch * 100 \
          if system.total_gesamtverbrauch else None

    night_min  = system.nighttime_verbrauch_sorted[-1] \
                 if system.nighttime_verbrauch_sorted else None

    h_cons = system.hourly_avg_consumption
    h_gen  = system.hourly_avg_generation

    # Spitzeneinspeisung = höchste durchschnittliche Einspeiseleistung einer Stunde
    peak_gen_kw = max((v for v in h_gen if v is not None), default=None)

    # Beste Stunde für Einspeisung = Stunde mit dem höchsten Gemeinschaftsverbrauch
    # (= wenn die Mitglieder am meisten Strom brauchen und Eigendeckung am wertvollsten ist)
    best_feed_hour = None
    if any(v is not None for v in h_cons):
        best_feed_hour = max(range(24), key=lambda h: h_cons[h] if h_cons[h] is not None else -1)

    # Beste Stunde für Autarkie = Stunde mit dem höchsten Autarkiegrad
    hourly_aut = system.hourly_autarkiegrad
    best_cons_hour = None
    if any(v is not None for v in hourly_aut):
        best_cons_hour = max(range(24), key=lambda h: hourly_aut[h] if hourly_aut[h] is not None else -1)

    # Netzbezug = Gesamtverbrauch − Eigendeckung
    netzbezug = (system.total_gesamtverbrauch - system.total_eigendeckung) \
                if (system.total_gesamtverbrauch is not None
                    and system.total_eigendeckung is not None) else None

    def fmt_pct(v):  return f'{v:.1f} %'   if v is not None else '–'
    def fmt_kw(v):   return f'{v:.2f} kW'  if v is not None else '–'
    def fmt_kwh(v):  return f'{v:,.1f} kWh'.replace(',', '.') if v is not None else '–'
    def fmt_hr(h):   return f'{h}:00 – {h+1}:00 Uhr' if h is not None else '–'

    # ── Typtagkurve ─────────────────────────────────────────────────────────
    chart_png = _make_typday_chart(h_cons, h_gen)

    # ── ReportLab Dokument ──────────────────────────────────────────────────
    doc = SimpleDocTemplate(
        output_path,
        pagesize=A4,
        leftMargin=1.8 * cm, rightMargin=1.8 * cm,
        topMargin=1.4 * cm, bottomMargin=1.4 * cm,
    )
    W = A4[0] - 3.6 * cm   # nutzbare Breite

    # ── Typografie ───────────────────────────────────────────────────────────
    sTitle = ParagraphStyle('Title', fontName='Helvetica-Bold',
                             fontSize=14, textColor=C_GREEN_DARK,
                             spaceAfter=1, leading=18, alignment=TA_LEFT)
    sSub   = ParagraphStyle('Sub',   fontName='Helvetica',
                             fontSize=9,  textColor=C_GRAY,
                             spaceAfter=0, alignment=TA_LEFT)
    sDate  = ParagraphStyle('Date',  fontName='Helvetica',
                             fontSize=8,  textColor=C_GRAY_MID,
                             spaceAfter=0, alignment=TA_RIGHT)
    sSmall = ParagraphStyle('Small', fontName='Helvetica',
                             fontSize=7.5, textColor=C_GRAY_MID, leading=11)
    sSection = ParagraphStyle('Section', fontName='Helvetica-Bold',
                               fontSize=9, textColor=C_GREEN_DARK,
                               spaceBefore=6, spaceAfter=4)

    # ── Große KPI-Hero-Kacheln (EVQ + Autarkiegrad) ─────────────────────────
    def hero_cell(value, label, unit_label, bg, text_color):
        """Erstellt eine große KPI-Kachel."""
        return Table(
            [
                [Paragraph(f'<b>{value}</b>',
                           ParagraphStyle('hv', fontName='Helvetica-Bold',
                                          fontSize=30, textColor=text_color,
                                          alignment=TA_CENTER, leading=34))],
                [Paragraph(label,
                           ParagraphStyle('hl', fontName='Helvetica-Bold',
                                          fontSize=9, textColor=text_color,
                                          alignment=TA_CENTER, leading=12))],
                [Paragraph(unit_label,
                           ParagraphStyle('hu', fontName='Helvetica',
                                          fontSize=7.5, textColor=C_GRAY_MID,
                                          alignment=TA_CENTER, leading=10))],
            ],
            colWidths=[W / 2 - 6],
            style=TableStyle([
                ('BACKGROUND',   (0, 0), (-1, -1), bg),
                ('TOPPADDING',   (0, 0), (-1, -1), 14),
                ('BOTTOMPADDING',(0, 0), (-1, -1), 14),
                ('LEFTPADDING',  (0, 0), (-1, -1), 8),
                ('RIGHTPADDING', (0, 0), (-1, -1), 8),
                ('ALIGN',        (0, 0), (-1, -1), 'CENTER'),
                ('VALIGN',       (0, 0), (-1, -1), 'MIDDLE'),
                ('ROUNDEDCORNERS', [6]),
            ])
        )

    hero_evq = hero_cell(
        fmt_pct(evq), 'Eigenverbrauchsquote',
        'Anteil der Erzeugung, der intern verbraucht wird',
        C_GREEN_LIGHT, C_GREEN_DARK
    )
    hero_aut = hero_cell(
        fmt_pct(aut), 'Autarkiegrad',
        'Anteil des Verbrauchs, der aus Eigenproduktion gedeckt wird',
        C_BLUE_LIGHT, C_BLUE_DARK
    )

    hero_table = Table(
        [[hero_evq, hero_aut]],
        colWidths=[W / 2, W / 2],
        style=TableStyle([
            ('LEFTPADDING',  (0, 0), (-1, -1), 4),
            ('RIGHTPADDING', (0, 0), (-1, -1), 4),
            ('TOPPADDING',   (0, 0), (-1, -1), 0),
            ('BOTTOMPADDING',(0, 0), (-1, -1), 0),
        ])
    )

    # ── Energiedaten-Tabelle ─────────────────────────────────────────────────
    # Einheitliche, zweispaltige Tabelle: Label | Wert
    HDR_BG  = C_GREEN_DARK
    HDR_TXT = C_WHITE

    def _row(label, value, alt=False):
        bg = C_ROW_ALT if alt else C_WHITE
        return [label, value, bg]

    energy_rows_raw = [
        _row('Erzeugte Solarenergie gesamt',
             fmt_kwh(system.total_gesamterzeugung)),
        _row('Davon für die Gemeinschaft nutzbar',
             fmt_kwh(system.total_erzeugung_tf), alt=True),
        _row('Verbrauch der Mitglieder',
             fmt_kwh(system.total_gesamtverbrauch)),
        _row('Davon direkt selbst gedeckt',
             fmt_kwh(system.total_eigendeckung), alt=True),
        _row('Zusätzlich vom öffentlichen Netz bezogen',
             fmt_kwh(netzbezug)),
        _row('Überschuss ans öffentliche Netz abgegeben',
             fmt_kwh(system.total_restüberschuss), alt=True),
        _row('Mindestverbrauch nachts',
             fmt_kw(night_min)),
        _row('Spitzeneinspeisung (Ø beste Stunde)',
             fmt_kw(peak_gen_kw), alt=True),
        _row('Stunde mit dem höchsten Stromverbrauch',
             fmt_hr(best_feed_hour)),
        _row('Stunde mit dem höchsten Eigendeckungsanteil',
             fmt_hr(best_cons_hour), alt=True),
    ]

    LABEL_W = W * 0.62
    VALUE_W = W * 0.38

    tbl_style_base = [
        ('FONTSIZE',    (0, 0), (-1, -1), 8.5),
        ('TOPPADDING',  (0, 0), (-1, -1), 5),
        ('BOTTOMPADDING',(0,0), (-1, -1), 5),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
        ('RIGHTPADDING',(0, 0), (-1, -1), 8),
        # Header
        ('BACKGROUND',  (0, 0), (-1, 0), HDR_BG),
        ('TEXTCOLOR',   (0, 0), (-1, 0), HDR_TXT),
        ('FONTNAME',    (0, 0), (-1, 0), 'Helvetica-Bold'),
        ('ALIGN',       (1, 0), (1, 0),  'RIGHT'),
        # Datenzeilen
        ('FONTNAME',    (0, 1), (0, -1), 'Helvetica'),
        ('FONTNAME',    (1, 1), (1, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR',   (0, 1), (0, -1), C_GRAY_DARK),
        ('TEXTCOLOR',   (1, 1), (1, -1), C_BLACK),
        ('ALIGN',       (1, 1), (1, -1), 'RIGHT'),
        # Rahmen
        ('LINEBELOW',   (0, 0), (-1, -2), 0.3, C_GRAY_LIGHT),
        ('BOX',         (0, 0), (-1, -1), 0.5, colors.HexColor('#cfd8dc')),
    ]

    # Hintergrundfarben für alternierende Zeilen (ab Zeile 1 = erste Datenzeile)
    row_bg_cmds = []
    for i, (_, _, bg) in enumerate(energy_rows_raw):
        row_bg_cmds.append(('BACKGROUND', (0, i + 1), (-1, i + 1), bg))

    header_row = [
        Paragraph('<font color="white"><b>Energiedaten der Periode</b></font>',
                  ParagraphStyle('th', fontName='Helvetica-Bold', fontSize=8.5,
                                 textColor=C_WHITE, alignment=TA_LEFT)),
        Paragraph('<font color="white"><b>Wert</b></font>',
                  ParagraphStyle('th2', fontName='Helvetica-Bold', fontSize=8.5,
                                 textColor=C_WHITE, alignment=TA_RIGHT)),
    ]
    data_rows = [
        [Paragraph(label, ParagraphStyle('td', fontName='Helvetica', fontSize=8.5,
                                         textColor=C_GRAY_DARK, leading=11)),
         Paragraph(value, ParagraphStyle('tv', fontName='Helvetica-Bold', fontSize=8.5,
                                         textColor=C_BLACK, alignment=TA_RIGHT, leading=11))]
        for label, value, _ in energy_rows_raw
    ]

    energy_table = Table(
        [header_row] + data_rows,
        colWidths=[LABEL_W, VALUE_W],
        style=TableStyle(tbl_style_base + row_bg_cmds)
    )

    # ── Typtagkurve ─────────────────────────────────────────────────────────
    img_buf  = io.BytesIO(chart_png)
    chart_img = Image(img_buf, width=W, height=W * 240 / 680)

    legend_data = [[
        Paragraph('<font color="#43a047">■</font>  Eigendeckung',
                  ParagraphStyle('leg', fontName='Helvetica', fontSize=7.5, textColor=C_GRAY)),
        Paragraph('<font color="#1565c0">■</font>  Netzbezug',
                  ParagraphStyle('leg', fontName='Helvetica', fontSize=7.5, textColor=C_GRAY)),
        Paragraph('<font color="#66bb6a">■</font>  Einspeise-Überschuss',
                  ParagraphStyle('leg', fontName='Helvetica', fontSize=7.5, textColor=C_GRAY)),
        Paragraph('<font color="#1565c0">─</font>  Ø Verbrauch   '
                  '<font color="#2e7d32">─</font>  Ø Erzeugung',
                  ParagraphStyle('leg', fontName='Helvetica', fontSize=7.5, textColor=C_GRAY)),
    ]]
    legend_table = Table(legend_data, colWidths=[W / 4] * 4,
                         style=TableStyle([
                             ('LEFTPADDING',  (0, 0), (-1, -1), 2),
                             ('RIGHTPADDING', (0, 0), (-1, -1), 2),
                             ('TOPPADDING',   (0, 0), (-1, -1), 2),
                             ('BOTTOMPADDING',(0, 0), (-1, -1), 2),
                         ]))

    # ── Story zusammenbauen ─────────────────────────────────────────────────
    story = [
        # ── Header: Name linksbündig, Datum rechtsbündig in einer Zeile ────
        Table(
            [[
                Paragraph(f'<b>{eeg_name}</b>', sTitle),
                Paragraph(f'Erstellt: {today}', sDate),
            ]],
            colWidths=[W * 0.65, W * 0.35],
            style=TableStyle([
                ('VALIGN',       (0, 0), (-1, -1), 'BOTTOM'),
                ('LEFTPADDING',  (0, 0), (-1, -1), 0),
                ('RIGHTPADDING', (0, 0), (-1, -1), 0),
                ('TOPPADDING',   (0, 0), (-1, -1), 0),
                ('BOTTOMPADDING',(0, 0), (-1, -1), 2),
            ])
        ),
        Paragraph('Globaler Gemeinschaftsbericht', sSub),
        HRFlowable(width=W, thickness=2, color=C_GREEN, spaceAfter=8),

        # ── Große KPI-Kacheln ────────────────────────────────────────────────
        hero_table,
        Spacer(1, 10),

        # ── Energie-Datentabelle ─────────────────────────────────────────────
        energy_table,
        Spacer(1, 10),

        # ── Typtagkurve ──────────────────────────────────────────────────────
        Paragraph('Typischer Lasttag der Energiegemeinschaft', sSection),
        Paragraph('Ø Leistung pro Stunde über alle Tage der Periode (15-Min-Mittelwerte)',
                  ParagraphStyle('cap2', fontName='Helvetica-Oblique', fontSize=7.5,
                                 textColor=C_GRAY, spaceAfter=4)),
        chart_img,
        legend_table,

        # ── Footer ───────────────────────────────────────────────────────────
        Spacer(1, 6),
        HRFlowable(width=W, thickness=0.5, color=C_GRAY_LIGHT, spaceAfter=4),
        Paragraph(
            'EVQ = Eigendeckung / Nutzbare Erzeugung × 100 %  ·  '
            'Autarkiegrad = Eigendeckung / Gesamtverbrauch × 100 %  ·  '
            'Spitzeneinspeisung = höchste Ø-Stundenleistung der Erzeugungsanlagen  ·  '
            'Nachtfenster = Sonnenuntergang bis Sonnenaufgang',
            sSmall
        ),
    ]

    doc.build(story)
    return output_path
