from __future__ import annotations

import tkinter as tk
from collections.abc import Callable
from datetime import date
from pathlib import Path
from tkinter import messagebox, ttk

from ccma.services.documents import DocumentError, DocumentService, GeneratedDocument
from ccma.storage.repository import MemberRepository, RepositoryError


class DocumentTemplateDialog(tk.Toplevel):
    def __init__(
        self,
        master: tk.Misc,
        repository: MemberRepository,
        member_id: str,
        on_generated: Callable[[Path], None],
        *,
        claim_id: str | None = None,
        reminder_id: str | None = None,
    ):
        super().__init__(master)
        self.service = DocumentService(repository)
        self.member_id = member_id
        self.claim_id = claim_id
        self.reminder_id = reminder_id
        self.on_generated = on_generated
        self.templates = self.service.compatible_templates(
            has_claim=claim_id is not None,
            has_reminder=reminder_id is not None,
        )
        self.template_by_label = {
            f"{template.name} ({template.relative_path})": template for template in self.templates
        }
        self.title("Dokument aus Template erzeugen")
        self.transient(master.winfo_toplevel())
        self.resizable(False, False)
        self.template_var = tk.StringVar()
        self.filename_var = tk.StringVar()
        self._build_ui()
        self.bind("<Escape>", lambda _event: self.destroy())
        self.after_idle(self._grab_if_visible)

    def _grab_if_visible(self) -> None:
        try:
            if self.winfo_exists() and self.winfo_viewable():
                self.grab_set()
        except tk.TclError:
            pass

    def _build_ui(self) -> None:
        frame = ttk.Frame(self, padding=18)
        frame.pack(fill="both", expand=True)
        ttk.Label(frame, text="OpenDocument-Template").grid(
            row=0, column=0, sticky="w", pady=5, padx=(0, 12)
        )
        template_box = ttk.Combobox(
            frame,
            textvariable=self.template_var,
            values=list(self.template_by_label),
            state="readonly",
            width=56,
        )
        template_box.grid(row=0, column=1, sticky="ew", pady=5)
        template_box.bind("<<ComboboxSelected>>", lambda _event: self._template_selected())
        ttk.Label(frame, text="PDF-Dateiname").grid(
            row=1, column=0, sticky="w", pady=5, padx=(0, 12)
        )
        ttk.Entry(frame, textvariable=self.filename_var, width=58).grid(
            row=1, column=1, sticky="ew", pady=5
        )
        context = "Mitglied"
        if self.claim_id:
            context += " · Forderung"
        if self.reminder_id:
            context += " · ausgewählte Mahnung"
        ttk.Label(frame, text=f"Kontext: {context}", style="Mono.TLabel").grid(
            row=2, column=0, columnspan=2, sticky="w", pady=(8, 0)
        )
        ttk.Label(
            frame,
            text="Das PDF wird unter files/documents in der Mitgliederakte abgelegt.",
            style="Muted.TLabel",
        ).grid(row=3, column=0, columnspan=2, sticky="w", pady=(4, 0))
        buttons = ttk.Frame(frame)
        buttons.grid(row=4, column=0, columnspan=2, sticky="e", pady=(18, 0))
        ttk.Button(buttons, text="Abbrechen", command=self.destroy).pack(side="left", padx=(0, 8))
        self.generate_button = ttk.Button(
            buttons,
            text="PDF erzeugen",
            style="Accent.TButton",
            command=self._generate,
        )
        self.generate_button.pack(side="left")
        if self.template_by_label:
            self.template_var.set(next(iter(self.template_by_label)))
            self._template_selected()
        else:
            self.generate_button.configure(state="disabled")
            ttk.Label(
                frame,
                text="Für diesen Kontext ist kein passendes Template vorhanden.",
                style="Warning.TLabel",
            ).grid(row=5, column=0, columnspan=2, sticky="w", pady=(12, 0))

    def _template_selected(self) -> None:
        template = self.template_by_label.get(self.template_var.get())
        if template:
            self.filename_var.set(f"{date.today().isoformat()} - {template.name}.pdf")

    def _generate(self) -> None:
        template = self.template_by_label.get(self.template_var.get())
        if template is None:
            messagebox.showerror("Template auswählen", "Bitte ein Template auswählen.", parent=self)
            return
        self.generate_button.configure(state="disabled")
        self.configure(cursor="watch")
        self.update_idletasks()
        try:
            generated: GeneratedDocument = self.service.generate(
                template,
                self.member_id,
                output_name=self.filename_var.get(),
                claim_id=self.claim_id,
                reminder_id=self.reminder_id,
            )
        except (DocumentError, RepositoryError, OSError) as exc:
            messagebox.showerror("Dokument konnte nicht erzeugt werden", str(exc), parent=self)
            self.generate_button.configure(state="normal")
            self.configure(cursor="")
            return
        self.destroy()
        self.on_generated(generated.path)
        messagebox.showinfo("Dokument erzeugt", f"PDF gespeichert:\n{generated.path}", parent=self.master)
