"""Wochenübersicht Excel export for DAK weekly summary sheets.

Generates .xlsx files matching the format sent to DAK for ICD code entry.
Two variants exist:
  - "c2s"     → Fallgruppen onko + intensiv (columns ZMO / ZMI)
  - "c2s_g_s" → Fallgruppen galle + sd     (columns Galle / Schild)

Each KW block has 4 header rows + data rows + 2 blank separator rows.
KWs are sorted descending (newest first).
"""

from __future__ import annotations

from datetime import date
from io import BytesIO
from typing import Any

from openpyxl import Workbook
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side

from app.services.excel_export import HEADER_FILL, HEADER_FONT

# ---------------------------------------------------------------------------
# Type configuration
# ---------------------------------------------------------------------------

WOCHENUEBERSICHT_TYPES: dict[str, dict[str, Any]] = {
    "c2s": {
        "fallgruppen": ("onko", "intensiv"),
        "fg_labels": ("ZMO", "ZMI"),
        "filename_infix": "c2s",
    },
    "c2s_g_s": {
        "fallgruppen": ("galle", "sd"),
        "fg_labels": ("Galle", "Schild"),
        "filename_infix": "c2s_g_s",
    },
}

# Column headers (row 4 of each KW block)
COL_HEADERS = [
    "KVNR",                                          # A
    "Datum",                                          # B
    "Erstgespräch",                                   # C
    "Zweitmeinung/Vorbereitung (bei Abbruch)",        # D
    "Zweitmeinung/Vorbereitung + Erteilung",          # E
    "Schriftliche Dokumentation (Gutachten)",          # F
    # G and H are dynamic (FG labels)
    # I = ICD-10
]

THIN_BORDER = Border(
    left=Side(style="thin"),
    right=Side(style="thin"),
    top=Side(style="thin"),
    bottom=Side(style="thin"),
)


def _kw_date_range(jahr: int, kw: int) -> tuple[date, date]:
    """Return (Monday, Sunday) for the given ISO year/week."""
    monday = date.fromisocalendar(jahr, kw, 1)
    sunday = date.fromisocalendar(jahr, kw, 7)
    return monday, sunday


def _format_date_range(monday: date, sunday: date) -> str:
    """Format as 'DD.MM. - DD.MM.YYYY'."""
    return f"{monday.strftime('%d.%m.')} - {sunday.strftime('%d.%m.%Y')}"


def generate_wochenuebersicht_xlsx(
    cases_by_kw: dict[int, list[Any]],
    export_type: str,
    jahr: int,
) -> bytes:
    """Generate a Wochenübersicht Excel workbook.

    Args:
        cases_by_kw: Cases grouped by calendar week number.
        export_type: One of ``"c2s"`` or ``"c2s_g_s"``.
        jahr: The report year.

    Returns:
        The ``.xlsx`` file contents as bytes.
    """
    type_cfg = WOCHENUEBERSICHT_TYPES[export_type]
    fg1, fg2 = type_cfg["fallgruppen"]
    fg1_label, fg2_label = type_cfg["fg_labels"]

    wb = Workbook()
    ws = wb.active
    ws.title = "Wochenübersicht"

    # Column widths
    ws.column_dimensions["A"].width = 14
    ws.column_dimensions["B"].width = 12
    ws.column_dimensions["C"].width = 14
    ws.column_dimensions["D"].width = 18
    ws.column_dimensions["E"].width = 18
    ws.column_dimensions["F"].width = 16
    ws.column_dimensions["G"].width = 10
    ws.column_dimensions["H"].width = 10
    ws.column_dimensions["I"].width = 14

    current_row = 1

    # Sort KWs descending (newest first)
    sorted_kws = sorted(cases_by_kw.keys(), reverse=True)

    for kw in sorted_kws:
        cases = cases_by_kw[kw]
        monday, sunday = _kw_date_range(jahr, kw)

        # --- Row 1: "Kalenderwoche:" label + number ---
        ws.cell(row=current_row, column=5, value="Kalenderwoche:")
        ws.cell(row=current_row, column=5).font = HEADER_FONT
        ws.cell(row=current_row, column=6, value=kw)
        ws.cell(row=current_row, column=6).font = HEADER_FONT
        current_row += 1

        # --- Row 2: Date range ---
        ws.cell(row=current_row, column=5, value=_format_date_range(monday, sunday))
        ws.cell(row=current_row, column=5).font = Font(italic=True)
        current_row += 1

        # --- Row 3: Instruction ---
        ws.cell(
            row=current_row,
            column=3,
            value="Bitte entsprechendes Feld mit x kennzeichnen",
        )
        ws.cell(row=current_row, column=3).font = Font(italic=True, color="FF808080")
        current_row += 1

        # --- Row 4: Column headers ---
        headers = COL_HEADERS + [fg1_label, fg2_label, "ICD-10"]
        for ci, header in enumerate(headers, start=1):
            cell = ws.cell(row=current_row, column=ci, value=header)
            cell.fill = HEADER_FILL
            cell.font = HEADER_FONT
            cell.border = THIN_BORDER
            cell.alignment = Alignment(wrap_text=True, vertical="center")
        current_row += 1

        # --- Data rows ---
        # Sort cases by datum ascending within each KW
        sorted_cases = sorted(cases, key=lambda c: (c.datum or date.min))

        for case in sorted_cases:
            # A: KVNR
            ws.cell(row=current_row, column=1, value=case.kvnr or "")
            # B: Datum
            ws.cell(
                row=current_row,
                column=2,
                value=case.datum.strftime("%d.%m.%Y") if case.datum else "",
            )
            # C: Erstgespräch — always x
            ws.cell(row=current_row, column=3, value="x")
            # D: Zweitmeinung/Vorbereitung (bei Abbruch)
            if case.ablehnung or case.abbruch:
                ws.cell(row=current_row, column=4, value="x")
            # E: Zweitmeinung/Vorbereitung + Erteilung
            if case.unterlagen and not case.ablehnung and not case.abbruch:
                ws.cell(row=current_row, column=5, value="x")
            # F: Schriftliche Dokumentation (Gutachten)
            if case.gutachten:
                ws.cell(row=current_row, column=6, value="x")
            # G: FG1 (ZMO / Galle)
            if case.fallgruppe == fg1:
                ws.cell(row=current_row, column=7, value="x")
            # H: FG2 (ZMI / Schild)
            if case.fallgruppe == fg2:
                ws.cell(row=current_row, column=8, value="x")
            # I: ICD-10
            ws.cell(row=current_row, column=9, value=case.icd or "")

            # Apply thin borders to data row
            for ci in range(1, 10):
                ws.cell(row=current_row, column=ci).border = THIN_BORDER
                ws.cell(row=current_row, column=ci).alignment = Alignment(
                    horizontal="center" if ci >= 3 else "left"
                )

            current_row += 1

        # --- 2 blank separator rows ---
        current_row += 2

    buf = BytesIO()
    wb.save(buf)
    return buf.getvalue()
