import abc
from Matching.MetricFactorys import UserMetricFactory


class AbstractMatcher(metaclass=abc.ABCMeta):
    """
    override get_metric and query_users to become concrete
    """

    def __init__(self, user):
        self.user = user
        self.metric = self.get_metric()

    def _is_matchable(self, user):
        if user.id == 1 or not user.moderation_flags.can_match:
            return False
        if not user.get_user_card():
            return False
        return user not in self.user.likes \
            and user not in self.user.dislikes \
            and user not in self.user.get_matched_users() \
            and not self.user == user

    def _get_umf(self, preferences=None):
        if preferences:
            return UserMetricFactory(preferences, self.user, )
        else:
            preferences = self.user.matching_preferences
            return UserMetricFactory(preferences, self.user)

    def get_more_matches(self, amount: int):
        if not self.user.moderation_flags.can_match:
            return []

        user_score_dict = []
        for user in self.query_users():
            if not self._is_matchable(user):
                continue
            user_score_dict.append((user, self.metric.get_score(user)))
        score_user_sorted = sorted(user_score_dict, key=lambda x: x[1], reverse=True)
        sorted_matches = [pair[0] for pair in score_user_sorted]

        if amount > len(sorted_matches):
            amount = len(sorted_matches)

        return sorted_matches[:amount]

    @abc.abstractmethod
    def get_metric(self):
        """
        returns a metric factory
        """

    @abc.abstractmethod
    def query_users(self):
        """
        returns list of users that could be matched
        """
