"""Generische Healing-Regelkarte.

Jede Karte der Healing-Seite wird aus einer Deklaration gebaut:
Titel und Schalter im Kartenkopf, darunter beliebige Felder
(Hotkey, Slot, Prozent-Slider, durchsuchbare Auswahl). Die
Widget-Logik lebt genau einmal hier — die Tabs deklarieren nur
noch, welche Kontext-Methoden mit welchen Keys verdrahtet sind.
"""
import customtkinter

from src.ui import theme
from src.ui.widgets import (
    Card, HotkeyEntry, PercentSlider, SearchableComboBox, positiveInt,
)


class HealingRuleCard(Card):
    """Karte, die ihre Felder komplett aus `spec` erzeugt.

    spec = {
        'title': str,
        'subtitle': str (optional),
        'toggle': {'get': ctx -> bool, 'set': (ctx, bool)} (optional),
        'fields': [field, ...]
    }

    field = {
        'type': 'hotkey' | 'slot' | 'slider' | 'combo',
        'label': str,
        'name': str (optional, Schluessel in self.widgets),
        'get': ctx -> Wert,
        'set': (ctx, Wert),
        # nur combo:
        'values': [str, ...],
        'placeholder': str (optional),
        'subtext': Wert -> str (optional, z. B. Mana-Kosten),
    }
    """

    def __init__(self, master, context, spec):
        self.context = context
        self.toggleSpec = spec.get('toggle')
        super().__init__(
            master, spec['title'], subtitle=spec.get('subtitle'),
            toggled=self._onToggle if self.toggleSpec else None,
            toggle_initial=(
                self.toggleSpec['get'](context) if self.toggleSpec else False
            ),
        )
        self.widgets = {}
        self._subtexts = {}
        self.body.grid_columnconfigure(0, weight=0)
        self.body.grid_columnconfigure(1, weight=1)
        self._row = 0
        for field in spec.get('fields', []):
            builder = getattr(self, f"_build{field['type'].capitalize()}")
            builder(field)

    # ------------------------------------------------------------- Toggle
    def _onToggle(self):
        self.toggleSpec['set'](self.context, self.toggle.get() == 1)

    # ------------------------------------------------------------- Felder
    def _label(self, field):
        customtkinter.CTkLabel(
            self.body, text=field['label'], font=theme.font(12),
            text_color=theme.MUTED, anchor='w',
        ).grid(row=self._row, column=0, sticky='w', padx=(0, 12), pady=4)

    def _buildHotkey(self, field):
        self._label(field)
        entry = HotkeyEntry(
            self.body, initial=str(field['get'](self.context) or ''),
            on_change=lambda key: field['set'](self.context, key),
            font=theme.font(13),
        )
        entry.grid(row=self._row, column=1, sticky='ew', pady=4)
        self._track(field, entry)
        self._row += 1

    def _buildSlot(self, field):
        self._label(field)
        entry = customtkinter.CTkEntry(
            self.body, font=theme.font(13), validate='key',
            validatecommand=(self.register(positiveInt), '%P'),
        )
        entry.insert(0, str(field['get'](self.context)))
        entry.bind(
            '<KeyRelease>', lambda _e: self._onSlotChange(field, entry))
        entry.grid(row=self._row, column=1, sticky='ew', pady=4)
        self._track(field, entry)
        self._row += 1

    def _onSlotChange(self, field, entry):
        value = entry.get()
        if value.isdigit() and int(value) > 0:
            field['set'](self.context, int(value))

    def _buildSlider(self, field):
        slider = PercentSlider(
            self.body, field['label'], value=field['get'](self.context),
            command=lambda value: field['set'](self.context, value),
        )
        slider.grid(row=self._row, column=0, columnspan=2,
                    sticky='ew', pady=4)
        self._track(field, slider)
        self._row += 1

    def _buildCombo(self, field):
        self._label(field)
        combo = SearchableComboBox(
            self.body, values=field['values'],
            placeholder=field.get('placeholder', 'Suchen …'),
            command=lambda value: self._onComboChange(field, value),
        )
        combo.grid(row=self._row, column=1, sticky='ew', pady=4)
        self._track(field, combo)
        self._row += 1
        initial = field['get'](self.context)
        if initial:
            combo.set(initial)
        if field.get('subtext'):
            subtext = customtkinter.CTkLabel(
                self.body, text='', font=theme.font(11),
                text_color=theme.MUTED, anchor='w',
            )
            subtext.grid(row=self._row, column=1, sticky='w')
            self._subtexts[id(field)] = subtext
            self._updateSubtext(field, initial)
            self._row += 1

    def _onComboChange(self, field, value):
        field['set'](self.context, value)
        self._updateSubtext(field, value)

    def _updateSubtext(self, field, value):
        label = self._subtexts.get(id(field))
        if label is not None:
            label.configure(text=field['subtext'](value) if value else '')

    def _track(self, field, widget):
        if field.get('name'):
            self.widgets[field['name']] = widget
