from math import log

from django.conf import settings

from staff.celery_app import app
from staff.lib.tasks import LockedTask
from staff.person.tasks.achievery import GiveAchievements

from .models import Log
from .notifications import KudosGivenNotification


@app.task(name='staff.kudos.tasks.AchKudosGivenTask')
class AchKudosGivenTask(GiveAchievements):
    """Задание, выдающее достижение за благодарности другим людям."""

    KUDOS_START_COUNT = 5
    """Количество благодарностей, начиная с которого выдаются значки."""

    @property
    def achievement_id(self):
        return settings.ACHIEVEMENT_KUDOS_GIVER_ID

    @classmethod
    def calculate_level(cls, kudos_count):
        """Возвращает уровень достижения, соответствующий
        указанному количеству благодарностей.

        Значок выдаётся, начиная с 5 (KUDOS_GIVE_START_COUNT) благодарностей.
        Далее уровень значка возрастает в геометрической прогрессии (знаменатель 2),
        получается:

            5 - 1 ур.
            10 - 2 ур.
            20 - 3 ур.
            40 - 4 ур.

        :param int kudos_count:
        :rtype: int

        """
        kudos_start = cls.KUDOS_START_COUNT

        if kudos_count < kudos_start:
            return 0

        return int(log(kudos_count / kudos_start, 2) + 1)

    def get_level(self, person):
        """
        :param Staff person:
        :rtype: Optional[int]
        """
        level = self.calculate_level(kudos_count=person.kudos_given.count())
        return level or None


@app.task(name='staff.kudos.tasks.MailKudosGivenTask')
class MailKudosGivenTask(LockedTask):
    """Задание, рассылающее оповещения получателям благодарностей."""

    def locked_run(self, log_ids, *args, **kwargs):
        log_entries = list(
            Log.objects
            .filter(id__in=log_ids)
            .select_related('issuer__login', 'recipient__work_email')
            .only('issuer__login', 'recipient__work_email', 'message')
        )

        if not log_entries:
            return

        # Рассматривается случай оповещения с учётом группового благодарения,
        # когда все записи в журнале имеют общее сообщение и благодарителя,
        # но разных получателей.
        log_entry = log_entries[0]

        KudosGivenNotification(
            target='@',
            context={
                'log_ids': log_ids,
                'issuer': log_entry.issuer.login,
                'message': log_entry.message,
            },

        ).send(recipients=[log_entry.recipient.work_email for log_entry in log_entries])
