import abc
from hearthbreaker.tags.base import Selector, Player, Picker, Function, Amount, Condition
import hearthbreaker.tags.condition


class FriendlyPlayer(Player):
    def match(self, source, obj):
        return obj.player is source.player

    def get_players(self, target):
        return [target]

    def __to_json__(self):
        return "friendly"


class EnemyPlayer(Player):
    def get_players(self, target):
        return [target.opponent]

    def match(self, source, obj):
        return obj.player is source.player.opponent

    def __to_json__(self):
        return "enemy"


class BothPlayer(Player):
    def match(self, source, obj):
        return True

    def get_players(self, target):
        return [target.opponent, target]

    def __to_json__(self):
        return "both"


class PlayerOne(Player):
    def match(self, source, obj):
        return obj.player is source.player.game.players[0]

    def get_players(self, target):
        return [target.game.players[0]]

    def __to_json__(self):
        return "player_one"


class PlayerTwo(Player):
    def match(self, source, obj):
        return obj.player is source.player.game.players[1]

    def get_players(self, target):
        return [target.game.players[1]]

    def __to_json__(self):
        return "player_two"


class CurrentPlayer(Player):
    def match(self, source, obj):
        return obj.player is source.player.game.current_player

    def get_players(self, target):
        return [target.game.current_player]

    def __to_json__(self):
        return "current_player"


class OtherPlayer(Player):
    def match(self, source, obj):
        return obj.player is source.player.game.other_player

    def get_players(self, target):
        return [target.game.other_player]

    def __to_json__(self):
        return "other_player"


class AllPicker(Picker):
    def pick(self, source, targets):
        return targets

    def __to_json__(self):
        return {
            'name': "all"
        }


class UserPicker(Picker):
    def pick(self, source, targets):
        if source.card.current_target:
            return [source.card.current_target]
        filtered_targets = [target for target in filter(lambda t: t.player is source.player or not t.stealth, targets)]
        if len(filtered_targets) > 0:
            source.card.current_target = source.player.agent.choose_target(filtered_targets)
            return [source.card.current_target]
        return filtered_targets

    def __to_json__(self):
        return {
            'name': "user"
        }


class RandomPicker(Picker):
    def __init__(self, count=1):
        self.count = count

    def pick(self, source, targets):
        for i in range(self.count):
            if len(targets) > 0:
                yield source.player.game.random_choice(targets)
            targets = [target for target in filter(lambda t: not (t.is_minion() and t.dead), targets)]

    def __to_json__(self):
        return {
            'name': "random",
            'count': self.count
        }


class CardSelector(Selector, metaclass=abc.ABCMeta):
    def __init__(self, players=FriendlyPlayer(), condition=None):
        self.players = players
        self.condition = condition

    def get_targets(self, source, obj=None):
        players = self.players.get_players(source.player)
        targets = []
        for p in players:
            for card in p.hand:
                if self.match(source, card):
                    targets.append(card)

        return targets

    def match(self, source, obj):
        if self.condition:
            return obj.is_card() and self.players.match(source, obj) and self.condition.evaluate(source, obj)
        return obj.is_card() and self.players.match(source, obj)

    def __to_json__(self):
        if self.condition:
            return {
                'name': 'card',
                'players': self.players,
                'condition': self.condition,
            }
        return {
            'name': 'card',
            'players': self.players
        }

    def __from_json__(self, players='friendly', condition=None):
        self.players = Player.from_json(players)
        if condition:
            self.condition = Condition.from_json(**condition)
        else:
            self.condition = None
        return self


class LastDrawnSelector(CardSelector):
    def __init__(self, players=FriendlyPlayer()):
        super().__init__(players)

    def get_targets(self, source, obj=None):
        if source.player.fatigue > 0:
            return []
        players = self.players.get_players(source.player)
        return [player.hand[-1] for player in players]

    def match(self, source, obj):
        return obj in self.get_targets(source, obj)

    def __to_json__(self):
        return {
            'name': 'last_drawn',
            'players': self.players
        }

    def __from_json__(self, players='friendly'):
        self.players = Player.from_json(players)
        return self


class HeroSelector(Selector):
    def __init__(self, players=FriendlyPlayer(), picker=AllPicker()):
        self.players = players
        self.picker = picker

    def get_targets(self, source, obj=None):
        return [p.hero for p in self.players.get_players(source.player)]

    def choose_targets(self, source, target=None):
        possible_targets = self.get_targets(source, target)
        return self.picker.pick(source, possible_targets)

    def match(self, source, obj):
        return obj.is_hero() and self.players.match(source, obj)

    def __to_json__(self):
        return {
            'name': 'hero',
            'players': self.players,
            'picker': self.picker
        }

    def __from_json__(self, picker, players='friendly'):
        self.players = Player.from_json(players)
        self.picker = Picker.from_json(**picker)
        return self


class PlayerSelector(Sele
ctor):
    def __init__(self, players=FriendlyPlayer()):
        self.players = players

    def get_targets(self, source, obj=None):
        return self.players.get_players(source.player)

    def match(self, source, obj):
        return source.player is obj

    def __to_json__(self):
        return {
            'na
me': 'player',
            'players': self.players
        }

    def __from_json__(self, players='friendly'):
        self.players = Player.from_json(players)
        return self


class MinionSelector(Selector):
    def __init__(self, condition=hearthbreaker.tags.condition.MinionIsNotTarget(), players=FriendlyPlayer(),
                 picker=AllPicker()):
        self.condition = condition
        self.players = players
        self.picker = picker

    def get_targets(self, source, obj=None):
        players = self.players.get_players(source.player)
        targets = []
        for p in players:
            for minion in p.minions:
                if self.match(source, minion):
                    targets.append(minion)

        return targets

    def choose_targets(self, source, target=None):
        possible_targets = self.get_targets(source, target)
        return self.picker.pick(source, possible_targets)

    def match(self, source, obj):
        if self.condition:
            return not obj.is_card() and obj.is_minion() and not obj.dead and self.players.match(source, obj)\
                and self.condition.evaluate(source, obj)
        else:
            return obj.is_minion() and self.players.match(source, obj) and not obj.dead

    def __to_json__(self):
        if self.condition:
            return {
                'name': 'minion',
                'condition': self.condition,
                'players': self.players,
                'picker': self.picker
            }
        return {
            'name': 'minion',
            'players': self.players,
            'picker': self.picker
        }

    def __from_json__(self, players, picker, condition=None):
        if condition:
            self.condition = hearthbreaker.tags.condition.Condition.from_json(**condition)
        else:
            self.condition = None
        self.players = Player.from_json(players)
        self.picker = Picker.from_j