import tkinter as tk
from collections import Counter
from collections.abc import Callable
from tkinter import messagebox, ttk

from ccma.domain.dates import format_date_for_display
from ccma.domain.models import MEMBERSHIP_STATUS_LABELS, HousekeeperFinding, Member


class DashboardTab(ttk.Frame):
    def __init__(
        self,
        master: tk.Misc,
        member_count: int,
        findings: list[HousekeeperFinding],
        on_housekeeper: Callable[[], None],
    ):
        super().__init__(master, padding=24)
        self.member_count = member_count
        self.findings = findings
        self.on_housekeeper = on_housekeeper
        self._build_ui()

    def _build_ui(self) -> None:
        self.columnconfigure(0, weight=1)
        ttk.Label(self, text="SYSTEM OVERVIEW", style="TabTitle.TLabel").grid(row=0, column=0, sticky="w")
        ttk.Label(self, text="Mitgliederverwaltung · lokaler File-Store", style="Mono.TLabel").grid(
            row=1, column=0, sticky="w", pady=(3, 22)
        )
        cards = ttk.Frame(self)
        cards.grid(row=2, column=0, sticky="ew")
        counts = Counter(finding.severity for finding in self.findings)
        values = [
            ("MITGLIEDER", str(self.member_count), ""),
            ("ACTION REQUIRED", str(counts["error"]), "CardError.TLabel"),
            ("DUE SOON", str(counts["warning"] + counts["info"]), "CardWarning.TLabel"),
            ("DATA INTEGRITY", "OK", ""),
        ]
        for column, (label, value, style) in enumerate(values):
            card = ttk.Frame(cards, style="Card.TFrame", padding=18)
            card.grid(row=0, column=column, sticky="nsew", padx=(0, 10))
            cards.columnconfigure(column, weight=1)
            ttk.Label(card, text=label, style="CardTitle.TLabel").pack(anchor="w")
            ttk.Label(card, text=value, style=style or "CardValue.TLabel").pack(anchor="w", pady=(8, 0))
        ttk.Button(self, text="Hausmeister öffnen", style="Accent.TButton", command=self.on_housekeeper).grid(
            row=3, column=0, sticky="w", pady=(24, 0)
        )

    def update_data(self, member_count: int, findings: list[HousekeeperFinding]) -> None:
        self.member_count = member_count
        self.findings = findings
        for child in self.winfo_children():
            child.destroy()
        self._build_ui()


class SearchResultsTab(ttk.Frame):
    def __init__(
        self,
        master: tk.Misc,
        query: str,
        members: list[Member],
        on_open: Callable[[str], None],
        on_close: Callable[[], None],
    ):
        super().__init__(master, padding=12)
        self.query = query
        self.members = members
        self.on_open = on_open
        self.on_close = on_close
        self._build_ui()

    def _build_ui(self) -> None:
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        header = ttk.Frame(self)
        header.grid(row=0, column=0, sticky="ew", pady=(0, 10))
        header.columnconfigure(0, weight=1)
        ttk.Label(header, text=f'Suche: "{self.query}"', style="TabTitle.TLabel").grid(
            row=0, column=0, sticky="w"
        )
        ttk.Label(header, text=f"{len(self.members)} Treffer", style="Mono.TLabel").grid(
            row=1, column=0, sticky="w"
        )
        ttk.Button(header, text="Tab schließen", command=self.on_close).grid(row=0, column=1, rowspan=2)
        tree = ttk.Treeview(self, columns=("number", "name", "email", "birth", "status"), show="headings")
        for key, title, width in (
            ("number", "Nummer", 90),
            ("name", "Name", 220),
            ("email", "E-Mail-Adresse", 260),
            ("birth", "Geburtsdatum", 110),
            ("status", "Status", 160),
        ):
            tree.heading(key, text=title)
            tree.column(key, width=width, anchor="w")
        tree.grid(row=1, column=0, sticky="nsew")
        for member in self.members:
            tree.insert(
                "",
                "end",
                iid=member.member_id,
                values=(
                    member.member_number,
                    member.display_name,
                    member.email,
                    format_date_for_display(member.birth_date),
                    MEMBERSHIP_STATUS_LABELS.get(member.status, member.status),
                ),
            )
        tree.bind("<Double-1>", lambda _event: self._open_selected(tree))
        tree.bind("<Return>", lambda _event: self._open_selected(tree))

    def _open_selected(self, tree: ttk.Treeview) -> None:
        selected = tree.selection()
        if selected:
            self.on_open(selected[0])


class MembersTab(ttk.Frame):
    def __init__(
        self,
        master: tk.Misc,
        members: list[Member],
        on_open: Callable[[str], None],
        on_close: Callable[[], None],
    ):
        super().__init__(master, padding=12)
        self.members = members
        self.on_open = on_open
        self.on_close = on_close
        self._build_ui()

    def _build_ui(self) -> None:
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        header = ttk.Frame(self)
        header.grid(row=0, column=0, sticky="ew", pady=(0, 10))
        header.columnconfigure(0, weight=1)
        ttk.Label(header, text="MITGLIEDER", style="TabTitle.TLabel").grid(row=0, column=0, sticky="w")
        self.count_var = tk.StringVar()
        ttk.Label(header, textvariable=self.count_var, style="Mono.TLabel").grid(row=1, column=0, sticky="w")
        ttk.Button(header, text="Tab schließen", command=self.on_close).grid(row=0, column=1, rowspan=2)
        self.tree = ttk.Treeview(
            self, columns=("number", "name", "email", "birth", "status"), show="headings"
        )
        for key, title, width in (
            ("number", "Nummer", 110),
            ("name", "Name", 230),
            ("email", "E-Mail-Adresse", 270),
            ("birth", "Geburtsdatum", 120),
            ("status", "Status", 170),
        ):
            self.tree.heading(key, text=title)
            self.tree.column(key, width=width, anchor="w")
        self.tree.grid(row=1, column=0, sticky="nsew")
        self.tree.bind("<Double-1>", lambda _event: self._open_selected())
        self.tree.bind("<Return>", lambda _event: self._open_selected())
        self.refresh(self.members)

    def refresh(self, members: list[Member]) -> None:
        self.members = members
        self.tree.delete(*self.tree.get_children())
        self.count_var.set(f"{len(members)} Mitglieder")
        for member in members:
            self.tree.insert(
                "",
                "end",
                iid=member.member_id,
                values=(
                    member.member_number,
                    member.display_name,
                    member.email,
                    format_date_for_display(member.birth_date),
                    MEMBERSHIP_STATUS_LABELS.get(member.status, member.status),
                ),
            )

    def _open_selected(self) -> None:
        selected = self.tree.selection()
        if selected:
            self.on_open(selected[0])


class HousekeeperTab(ttk.Frame):
    def __init__(
        self,
        master: tk.Misc,
        findings: list[HousekeeperFinding],
        on_open_member: Callable[[str], None],
        on_refresh: Callable[[], list[HousekeeperFinding]],
        on_delete: Callable[[str], list[HousekeeperFinding]],
        on_close: Callable[[], None],
    ):
        super().__init__(master, padding=12)
        self.findings = findings
        self.on_open_member = on_open_member
        self.on_refresh = on_refresh
        self.on_delete = on_delete
        self.on_close = on_close
        self._build_ui()

    def _build_ui(self) -> None:
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        header = ttk.Frame(self)
        header.grid(row=0, column=0, sticky="ew", pady=(0, 10))
        header.columnconfigure(0, weight=1)
        self.title_var = tk.StringVar()
        ttk.Label(header, textvariable=self.title_var, style="TabTitle.TLabel").grid(
            row=0, column=0, sticky="w"
        )
        ttk.Label(
            header,
            text="Regeln prüfen Daten und führen idempotente Aktionen aus",
            style="Mono.TLabel",
        ).grid(row=1, column=0, sticky="w")
        ttk.Button(header, text="Neu prüfen", command=self.refresh).grid(
            row=0, column=1, rowspan=2, padx=(0, 8)
        )
        ttk.Button(header, text="Tab schließen", command=self.on_close).grid(row=0, column=2, rowspan=2)
        self.tree = ttk.Treeview(self, columns=("severity", "title", "detail", "due"), show="headings")
        for key, title, width in (
            ("severity", "Level", 90),
            ("title", "Vorgang", 330),
            ("detail", "Details", 390),
            ("due", "Fällig", 110),
        ):
            self.tree.heading(key, text=title)
            self.tree.column(key, width=width, anchor="w")
        self.tree.grid(row=1, column=0, sticky="nsew")
        self.tree.bind("<Double-1>", lambda _event: self._open_selected())
        self.tree.bind("<<TreeviewSelect>>", lambda _event: self._show_selected_details())
        details = ttk.LabelFrame(self, text="Details", padding=12)
        details.grid(row=2, column=0, sticky="ew", pady=(10, 0))
        details.columnconfigure(0, weight=1)
        self.detail_var = tk.StringVar(value="Eintrag auswählen, um Details anzuzeigen.")
        self.detail_label = ttk.Label(
            details,
            textvariable=self.detail_var,
            anchor="nw",
            justify="left",
            wraplength=800,
            style="Status.TLabel",
        )
        self.detail_label.grid(row=0, column=0, sticky="ew")
        self.delete_button = ttk.Button(
            details,
            text="Task löschen",
            command=self._delete_selected,
            state="disabled",
        )
        self.delete_button.grid(row=0, column=1, sticky="ne", padx=(12, 0))
        details.bind(
            "<Configure>",
            lambda event: self.detail_label.configure(wraplength=max(300, event.width - 32)),
        )
        self._render()

    def refresh(self) -> None:
        self.findings = self.on_refresh()
        self._render()

    def _render(self) -> None:
        self.tree.delete(*self.tree.get_children())
        self.detail_var.set("Eintrag auswählen, um Details anzuzeigen.")
        self.delete_button.configure(state="disabled")
        self.title_var.set(f"HAUSMEISTER · {len(self.findings)} Vorgänge")
        for index, finding in enumerate(self.findings):
            self.tree.insert(
                "",
                "end",
                iid=str(index),
                values=(finding.severity.upper(), finding.title, finding.detail, finding.due_date or ""),
            )

    def _show_selected_details(self) -> None:
        selected = self.tree.selection()
        if not selected:
            self.detail_var.set("Eintrag auswählen, um Details anzuzeigen.")
            self.delete_button.configure(state="disabled")
            return
        index = int(selected[0])
        if index >= len(self.findings):
            return
        self.detail_var.set(_finding_details(self.findings[index]))
        self.delete_button.configure(state="normal" if self.findings[index].key else "disabled")

    def _delete_selected(self) -> None:
        selected = self.tree.selection()
        if not selected:
            return
        finding = self.findings[int(selected[0])]
        if not finding.key or not messagebox.askyesno(
            "Hausmeister-Task löschen",
            f"Task wirklich löschen?\n\n{finding.title}\n\n"
            "Falls die Ursache weiter besteht, wird er beim nächsten Lauf neu angelegt.",
            parent=self,
        ):
            return
        self.findings = self.on_delete(finding.key)
        self._render()

    def _open_selected(self) -> None:
        selected = self.tree.selection()
        if selected:
            self.on_open_member(self.findings[int(selected[0])].member_id)


def _finding_details(finding: HousekeeperFinding) -> str:
    lines = [f"{finding.severity.upper()} · {finding.code}", finding.title]
    if finding.key:
        lines.append(f"Key: {finding.key}")
    if finding.due_date:
        lines.append(f"Fällig: {format_date_for_display(finding.due_date.isoformat())}")
    if finding.detail:
        lines.extend(("", finding.detail))
    return "\n".join(lines)
