from time import time

from .typings import Context

TEMP_IGNORE_SECONDS = 30


def ignoreCreatureTemporarily(
        context: Context, name: str, seconds: int = TEMP_IGNORE_SECONDS):
    """Legt eine Kreatur fuer `seconds` auf die Angriffs-Sperrliste.

    Gegenstueck zur BBot-Blacklist: Kreaturen, deren Angriff nicht
    bestaetigt wird (unerreichbar, Klick verfehlt), werden kurzfristig
    uebersprungen, damit der Bot das naechste Ziel nimmt.
    """
    ignored = context['ng_targeting'].setdefault('tempIgnored', {})
    ignored[name] = time() + seconds


def _isTempIgnored(context: Context, name: str) -> bool:
    ignored = context['ng_targeting'].get('tempIgnored') or {}
    expiry = ignored.get(name)
    if expiry is None:
        return False
    if expiry <= time():
        del ignored[name]
        return False
    return True


def getAttackableCreatures(context: Context):
    monsters = [
        monster for monster in context['gameWindow']['monsters']
        if not _isTempIgnored(context, monster['name'])
    ]
    if context['ng_targeting']['canIgnoreCreatures'] is False:
        return monsters
    settings = context['ng_targeting']['creatures']
    if settings:
        return sorted(
            [monster for monster in monsters if monster['name'] in settings and not settings[monster['name']]['ignore']],
            key=lambda monster: settings[monster['name']].get('priority', 1),
        )
    return [monster for monster in monsters if monster['name'] not in context['ignorable_creatures']]


def getFirstCreatureOnPath(creatures, path, excludedCoordinate=None):
    pathIndexes = {}
    for index, coordinate in enumerate(path):
        if coordinate is None or any(value is None for value in coordinate):
            continue
        pathIndexes[tuple(coordinate)] = index

    firstCreature = None
    firstIndex = None
    for creature in creatures:
        coordinate = creature.get('coordinate')
        if coordinate is None or any(value is None for value in coordinate):
            continue
        if excludedCoordinate is not None and tuple(coordinate) == tuple(excludedCoordinate):
            continue
        index = pathIndexes.get(tuple(coordinate))
        if index is not None and (firstIndex is None or index < firstIndex):
            firstCreature = creature
            firstIndex = index
    return firstCreature


# TODO: add unit tests
def hasCreaturesToAttack(context: Context) -> bool:
    context['ng_targeting']['hasIgnorableCreatures'] = False
    if len(context['gameWindow']['monsters']) == 0:
        context['ng_targeting']['canIgnoreCreatures'] = True
        return False
    attackable = getAttackableCreatures(context)
    context['ng_targeting']['hasIgnorableCreatures'] = len(attackable) < len(
        context['gameWindow']['monsters']
    )
    return bool(attackable)
