from src.gameplay.healing import syncHotkeys


def _config():
    return {'healing': {
        'potions': {
            'firstHealthPotion': {'enabled': True, 'hotkey': 'F1', 'slot': 1, 'item': None},
            'firstManaPotion': {'enabled': True, 'hotkey': 'F2', 'slot': 2, 'item': None},
        },
        'spells': {
            'criticalHealing': {'enabled': True, 'hotkey': '5', 'spell': 'exura vita'},
            'lightHealing': {'enabled': True, 'hotkey': '7', 'spell': 'exura gran'},
            'utura': {'enabled': False, 'hotkey': '8', 'spell': None},
            'uturaGran': {'enabled': False, 'hotkey': '9', 'spell': None},
        },
    }}


def _mockDetection(mocker, items, spells=None, tools=None):
    mocker.patch.object(syncHotkeys, 'detectSlotItems', return_value=items)
    mocker.patch.object(syncHotkeys, 'detectSlotSpells', return_value=spells)
    # Werkzeuge (Seil, Schaufel) werden getrennt erkannt und muessen hier
    # mit abgefangen werden - sonst laeuft die echte Bilderkennung gegen
    # das Platzhalter-Bild dieser Tests.
    mocker.patch.object(syncHotkeys, 'detectSlotTools', return_value=tools)


def test_assigns_detected_slots(mocker):
    _mockDetection(mocker, {266: 3, 268: 7})
    config = _config()

    ok, message = syncHotkeys.syncActionBar([], config)

    assert ok is True
    assert config['ng_actionBar']['smartHotkeys'] is True
    assert config['ng_actionBar']['slots'] == {'266': 3, '268': 7}
    health = config['healing']['potions']['firstHealthPotion']
    mana = config['healing']['potions']['firstManaPotion']
    assert health['slot'] == 3
    assert health['item'] == 266
    assert mana['slot'] == 7
    assert mana['item'] == 268
    assert 'Health Potion' in message
    assert 'Mana Potion' in message


def test_assigns_detected_spell_slots(mocker):
    _mockDetection(mocker, {266: 3, 268: 7}, {'exura vita': 1, 'utura': 11})
    config = _config()

    ok, message = syncHotkeys.syncActionBar([], config)

    assert ok is True
    spells = config['healing']['spells']
    assert spells['criticalHealing']['slot'] == 1
    assert spells['lightHealing']['slot'] is None
    assert spells['utura']['slot'] == 11
    assert spells['uturaGran']['slot'] is None
    assert 'exura vita → Slot 1' in message
    assert 'Zauber per Chat: exura gran' in message


def test_configured_item_is_preferred_over_default(mocker):
    _mockDetection(mocker, {239: 4, 268: 7})
    config = _config()
    config['healing']['potions']['firstHealthPotion']['item'] = 239

    ok, message = syncHotkeys.syncActionBar([], config)

    assert ok is True
    assert config['healing']['potions']['firstHealthPotion']['slot'] == 4
    assert 'Great Health Potion' in message


def test_missing_potion_keeps_hotkey_fallback(mocker):
    _mockDetection(mocker, {268: 7})
    config = _config()

    ok, message = syncHotkeys.syncActionBar([], config)

    assert ok is True
    assert config['healing']['potions']['firstHealthPotion']['slot'] is None
    assert 'nicht auf der Action Bar' in message


def test_no_action_bar_found(mocker):
    _mockDetection(mocker, None)

    ok, message = syncHotkeys.syncActionBar([], _config())

    assert ok is False
    assert 'Keine Action Bar' in message


def test_assigns_combo_spell_slots(mocker):
    _mockDetection(mocker, {266: 3, 268: 7}, {'exori': 9})
    config = _config()
    config['ng_comboSpells'] = {'enabled': True, 'items': [
        {'enabled': True, 'spells': [
            {'name': 'exori', 'hotkey': 'F9'},
            {'name': 'exori gran', 'hotkey': 'F10'},
        ]},
    ]}

    ok, _ = syncHotkeys.syncActionBar([], config)

    assert ok is True
    spells = config['ng_comboSpells']['items'][0]['spells']
    assert spells[0]['slot'] == 9
    assert spells[1]['slot'] is None


def test_seeds_supply_rules_when_refill_label_exists(mocker):
    _mockDetection(mocker, {266: 3, 268: 7})
    config = _config()
    config['ng_cave'] = {'waypoints': {'items': [
        {'label': 'Hunt'}, {'label': 'Refill'},
    ]}}

    ok, message = syncHotkeys.syncActionBar([], config)

    assert ok is True
    supplies = config['ng_supplies']
    assert supplies['enabled'] is True
    rules = supplies['rules']
    assert len(rules) == 2
    assert rules[0] == {
        'source': 'item', 'itemId': 266, 'operator': '<', 'target': 25,
        'label': 'refill', 'enabled': True,
    }
    assert rules[1]['itemId'] == 268
    assert 'Vorrats-Wächter' in message


def test_no_supply_seed_without_refill_label(mocker):
    _mockDetection(mocker, {266: 3, 268: 7})
    config = _config()
    config['ng_cave'] = {'waypoints': {'items': [{'label': 'Hunt'}]}}

    ok, _ = syncHotkeys.syncActionBar([], config)

    assert ok is True
    assert 'ng_supplies' not in config


def test_reports_detected_tools(mocker):
    """Seil und Schaufel landen in der Slot-Tabelle und in der Meldung."""
    _mockDetection(mocker, {266: 3}, tools={3457: 10, 3003: 11})
    config = _config()

    ok, message = syncHotkeys.syncActionBar([], config)

    assert ok is True
    slots = config['ng_actionBar']['slots']
    assert slots['3457'] == 10
    assert slots['3003'] == 11
    assert 'Shovel (Slot 10)' in message
    assert 'Rope (Slot 11)' in message
