"""Smart-Hotkey-Sync: Action Bar scannen und Config verknuepfen.

Erkennt per Icon-Matching, welcher Trank/Zauber in welchem Action-Bar-Slot
liegt, und schreibt das Ergebnis in die Profil-Config:
- ng_actionBar.slots: {item_id: slot} (komplette Item-Karte)
- ng_actionBar.smartHotkeys: True (Traenke/Zauber laufen dann ueber
  Slot-Klick bzw. Chat-Worte statt client-seitiger Hotkey-Belegung)
- healing.potions.*.slot: Slot des konfigurierten Tranks (Fallback: Hotkey)
- healing.spells.*.slot: Slot des konfigurierten Zaubers
  (Fallback: Chat-Zauber, danach Hotkey)
"""
from src.repositories.actionBar.slotIcons import (
    HEALTH_POTION_IDS, MANA_POTION_IDS, SLOT_ITEMS, SLOT_TOOLS,
    detectSlotItems, detectSlotSpells, detectSlotTools,
)

DEFAULT_HEALTH_POTION_ID = 266
DEFAULT_MANA_POTION_ID = 268


def _assignPotionSlot(potion, detected, allowedIds, defaultId):
    itemId = potion.get('item') or defaultId
    if itemId not in allowedIds:
        itemId = defaultId
    if itemId in detected:
        potion['item'] = itemId
        potion['slot'] = detected[itemId]
        return f'{SLOT_ITEMS[itemId]} → Slot {detected[itemId]}'
    # Kein Slot-Klick ohne gesicherten Treffer — Hotkey-Fallback bleibt.
    potion['slot'] = None
    return f'{SLOT_ITEMS.get(itemId, itemId)} nicht auf der Action Bar gefunden'


def _spellName(value):
    if isinstance(value, dict):
        return value.get('name')
    return value


def _assignSpellSlots(spellsConfig, detectedSpells):
    assigned = []
    missing = []
    for key in ('criticalHealing', 'lightHealing', 'mediumHealing', 'utura', 'uturaGran'):
        rule = spellsConfig.get(key)
        if rule is None:
            continue
        spell = _spellName(rule.get('spell'))
        if key == 'utura':
            spell = 'utura'
        elif key == 'uturaGran':
            spell = 'utura gran'
        if not spell:
            continue
        if detectedSpells is not None and spell in detectedSpells:
            rule['slot'] = detectedSpells[spell]
            assigned.append(f'{spell} → Slot {detectedSpells[spell]}')
        else:
            rule['slot'] = None
            missing.append(spell)
    return assigned, missing


def _assignComboSlots(comboItems, detectedSpells):
    """Verknuepft Combo-Zauber mit ihren erkannten Slots (still)."""
    for combo in comboItems:
        for spell in combo.get('spells', []):
            name = spell.get('name')
            if not name:
                continue
            if detectedSpells is not None and name in detectedSpells:
                spell['slot'] = detectedSpells[name]
            else:
                spell['slot'] = None


_REFILL_LABEL_CANDIDATES = ('refill', 'resupply', 'potion', 'potions', 'buy', 'shop')


def _seedSupplyRules(config):
    """Legt Standard-Vorratsregeln an, wenn die Route ein Refill-Label hat.

    ponytail: nur wenn noch keine Regel fuer das Item existiert; Schwelle
    25 als sinnvoller Startwert (Upgrade-Trigger: Schwellen-Lernen aus
    Verbrauch).
    """
    waypoints = config.get('ng_cave', {}).get('waypoints', {}).get('items', [])
    labels = {
        (waypoint.get('label') or '').lower()
        for waypoint in waypoints if waypoint.get('label')
    }
    label = next(
        (candidate for candidate in _REFILL_LABEL_CANDIDATES
         if candidate in labels),
        None,
    )
    if label is None:
        return False
    supplies = config.setdefault('ng_supplies', {})
    rules = supplies.setdefault('rules', [])
    seeded = False
    potions = config['healing']['potions']
    for key in ('firstHealthPotion', 'firstManaPotion'):
        itemId = potions[key].get('item')
        if itemId is None:
            continue
        if any(rule.get('itemId') == itemId for rule in rules):
            continue
        rules.append({
            'source': 'item', 'itemId': itemId, 'operator': '<',
            'target': 25, 'label': label, 'enabled': True,
        })
        seeded = True
    if seeded and 'enabled' not in supplies:
        supplies['enabled'] = True
    return seeded


def syncActionBar(screenshot, config):
    """Scannt die Action Bar und verknuepft Slots in `config`.

    Rueckgabe: (ok, message) — message ist direkt UI-tauglich.
    """
    detected = detectSlotItems(screenshot)
    if detected is None:
        return False, 'Keine Action Bar gefunden.'
    actionBar = config.setdefault('ng_actionBar', {})
    # Werkzeuge (Seil, Schaufel) werden getrennt erkannt - eigener
    # Bildbereich, siehe detectSlotTools. Sie landen in derselben
    # Slot-Tabelle, damit der Bot sie ueber den Slot benutzen kann und
    # kein Tastenkuerzel gepflegt werden muss.
    werkzeuge = detectSlotTools(screenshot) or {}
    detected = {**detected, **werkzeuge}
    actionBar['slots'] = {str(itemId): slot for itemId, slot in detected.items()}
    actionBar['smartHotkeys'] = True
    potions = config['healing']['potions']
    parts = [
        _assignPotionSlot(
            potions['firstHealthPotion'], detected,
            HEALTH_POTION_IDS, DEFAULT_HEALTH_POTION_ID),
        _assignPotionSlot(
            potions['firstManaPotion'], detected,
            MANA_POTION_IDS, DEFAULT_MANA_POTION_ID),
    ]
    spellsConfig = config['healing'].get('spells')
    detectedSpells = detectSlotSpells(screenshot)
    if spellsConfig is not None:
        assigned, missing = _assignSpellSlots(spellsConfig, detectedSpells)
        parts.extend(assigned)
        if missing:
            parts.append(f'Zauber per Chat: {", ".join(missing)}')
    comboConfig = config.get('ng_comboSpells')
    if comboConfig is not None:
        _assignComboSlots(comboConfig.get('items', []), detectedSpells)
    if werkzeuge:
        parts.append('Werkzeug: ' + ', '.join(
            f'{SLOT_TOOLS[itemId]} (Slot {slot})'
            for itemId, slot in sorted(werkzeuge.items(), key=lambda e: e[1])))
    if _seedSupplyRules(config):
        parts.append('Vorrats-Wächter: <25 → Refill')
    return True, ' · '.join(parts)
