import baseimpl.base
from django.db.models import Sum
from tasks.models import Campaign as DjangoCampaign
from tasks.models import Stats as DjangoStats
from tasks.models import Task as DjangoTask
from tasks.models import CampaignTask


class Campaign(baseimpl.base.BaseCampaign):
    def __init__(self, start, period_days):
        super().__init__(start, period_days)
        self.campaign = DjangoCampaign.objects.create(start=start, period_days=period_days)
        self._stats = Stats(self)

    @property
    def start(self):
        return self.campaign.start

    @property
    def tasks(self):
        return self.campaign.campaigntask_set.all()

    def mark_completed(self, user, task, period=None, date=None):
        if date is not None:
            period = self.period(date)
        if period is None:
            period = self.periods
        self.stats.mark_completed(user, period, task)

    @property
    def stats(self):
        return self._stats

    def add_task(self, task):
        task, created = DjangoTask.objects.get_or_create(name=task.name, description=task.description)
        # TODO add .tasks field in campaign to simplify this
        ctask = CampaignTask.objects.create(campaign=self.campaign, task=task, order=1)
        self.campaign.campaigntask_set.add(ctask)

    @property
    def period_days(self):
        return self.campaign.period_days


class Stats(baseimpl.base.BaseStats):
    def _get_stat(self, key):
        stat, _ = DjangoStats.objects.get_or_create(key=key)
        return stat

    def get_user_period_task_score(self, user, period, task):
        return self._get_stat(self.makekey(user=user, period=period, task=task)).score

    def get_user_period_score(self, user, period):
        return self._get_stat(self.makekey(user=user, period=period)).score

    def get_user_score(self, user):
        return self._get_stat(self.makekey(user=user)).score

    def get_team_period_task_score(self, team, period, task):
        return self._get_stat(self.makekey(team=team, period=period, task=task)).score

    def get_team_period_score(self, team, period):
        return self._get_stat(self.makekey(team=team, period=period)).score

    def get_team_score(self, team):
        return self._get_stat(self.makekey(team=team)).score

    def update_user_period_task_score(self, user, period, task):
        key = self.makekey(user=user, period=period, task=task)
        stat = self._get_stat(key)
        stat.score = 1
        stat.save()

    def update_user_period_score(self, user, period):
        key = self.makekey(user=user, period=period)
        total = DjangoStats.objects.filter(key__startswith=key + '.').aggregate(total=Sum('score'))['total']
        stat = self._get_stat(key)
        stat.score = total / len(self.campaign.tasks)
        stat.save()

    def update_user_score(self, user):
        key = self.makekey(user=user)
        total = sum([self.get_user_period_score(user, period + 1) for period in range(self.campaign.periods)])
        stat = self._get_stat(key)
        stat.score = total / self.campaign.periods
        stat.save()

    def update_team_period_task_score(self, team, period, task):
        key = self.makekey(team=team, period=period, task=task)
        user_scores = sum([self.get_user_period_task_score(user, period, task) for user in team.users])
        stat = self._get_stat(key)
        stat.score = user_scores / len(team.users)
        stat.save()

    def update_team_period_score(self, team, period):
        key = self.makekey(team, period)
        user_scores = sum([self.get_user_period_score(user, period) for user in team.users])
        stat = self._get_stat(key)
        stat.score = user_scores / len(team.users)
        stat.save()

    def update_team_score(self, team):
        key = self.makekey(team)
        total = sum([self.get_team_period_score(team, period + 1) for period in range(self.campaign.periods)])
        stat = self._get_stat(key)
        stat.score = total / self.campaign.periods
        stat.save()

    def makekey(self, user=None, team=None, period=None, task=None):
        key = '.'.join([str(x) for x in (user, team, period, task) if x])
        return key
