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

from ccma.domain.dates import age_label, date_input_hint
from ccma.domain.models import Member
from ccma.storage.repository import MemberRepository, RepositoryError


class NewMemberDialog(tk.Toplevel):
    def __init__(self, master: tk.Misc, repository: MemberRepository, on_created: Callable[[Member], None]):
        super().__init__(master)
        self.repository = repository
        self.on_created = on_created
        self.title("Neue Mitgliederakte")
        self.transient(master.winfo_toplevel())
        self.grab_set()
        self.resizable(False, False)
        self.number_policy = repository.get_member_number_policy()
        self.variables = {
            name: tk.StringVar()
            for name in ("first_name", "last_name", "email", "phone", "birth_date", "member_number")
        }
        self._build_ui()
        self.bind("<Escape>", lambda _event: self.destroy())
        self.bind("<Return>", lambda _event: self._create())
        self.after_idle(self._focus_first)

    def _build_ui(self) -> None:
        frame = ttk.Frame(self, padding=18)
        frame.pack(fill="both", expand=True)
        fields = [
            ("Vorname *", "first_name"),
            ("Nachname *", "last_name"),
            ("E-Mail-Adresse", "email"),
            ("Telefonnummer", "phone"),
            (f"Geburtsdatum ({date_input_hint()})", "birth_date"),
        ]
        if self.number_policy["mode"] == "manual":
            fields.append(("Mitgliedsnummer *", "member_number"))
        self.entries: dict[str, ttk.Entry] = {}
        for row, (label, key) in enumerate(fields):
            ttk.Label(frame, text=label).grid(row=row, column=0, sticky="w", pady=5, padx=(0, 12))
            if key == "birth_date":
                birth_row = ttk.Frame(frame)
                birth_row.grid(row=row, column=1, sticky="ew", pady=5)
                birth_row.columnconfigure(0, weight=1)
                entry = ttk.Entry(birth_row, textvariable=self.variables[key], width=24)
                entry.grid(row=0, column=0, sticky="ew")
                self.birth_age_var = tk.StringVar(value="Alter: —")
                ttk.Label(birth_row, textvariable=self.birth_age_var, style="Mono.TLabel").grid(
                    row=0, column=1, sticky="w", padx=(10, 0)
                )
                self.variables[key].trace_add(
                    "write",
                    lambda *_args: self.birth_age_var.set(age_label(self.variables["birth_date"].get())),
                )
            else:
                entry = ttk.Entry(frame, textvariable=self.variables[key], width=38)
                entry.grid(row=row, column=1, sticky="ew", pady=5)
            self.entries[key] = entry
        button_row = len(fields)
        if self.number_policy["mode"] == "automatic":
            preview = self.repository.preview_member_number(self.number_policy["pattern"])
            ttk.Label(frame, text="Mitgliedsnummer").grid(
                row=button_row, column=0, sticky="w", pady=5, padx=(0, 12)
            )
            ttk.Label(frame, text=f"Automatisch: {preview}", style="TimelineHeader.TLabel").grid(
                row=button_row, column=1, sticky="w", pady=5
            )
            button_row += 1
        buttons = ttk.Frame(frame)
        buttons.grid(row=button_row, column=0, columnspan=2, sticky="e", pady=(16, 0))
        ttk.Button(buttons, text="Abbrechen", command=self.destroy).pack(side="left", padx=(0, 8))
        ttk.Button(buttons, text="Akte anlegen", style="Accent.TButton", command=self._create).pack(
            side="left"
        )

    def _focus_first(self) -> None:
        self.entries["first_name"].focus_set()

    def _create(self) -> None:
        try:
            member = self.repository.create_member(
                **{key: variable.get() for key, variable in self.variables.items()}
            )
        except RepositoryError as exc:
            messagebox.showerror("Akte konnte nicht angelegt werden", str(exc), parent=self)
            return
        self.destroy()
        self.on_created(member)
