from intranet.femida.src.candidates.models import Challenge
from intranet.femida.src.comments.models import Comment
from intranet.femida.src.interviews.models import Interview
from intranet.femida.src.notifications.base import R, FetchingNotificationBase
from intranet.femida.src.notifications.utils import (
    get_candidate_message_id,
    get_problem_message_id,
    get_candidate_email_subject,
    get_interview_email_subject,
    get_problem_email_subject,
)
from intranet.femida.src.problems.models import Complaint


def _get_created_by(notification):
    related_object = notification.instance.related_object
    created_by = getattr(related_object, 'created_by', None)
    if created_by is not None:
        return [created_by.email]
    return []


def _get_interviewers(notification):
    related_object = notification.instance.related_object
    if isinstance(related_object, Interview):
        return [related_object.interviewer.email]
    elif isinstance(related_object, Challenge):
        return [related_object.reviewed_by.email]
    return []


def _get_thread_participants(notification):
    return set(
        Comment.objects
        .filter(
            content_type=notification.instance.content_type,
            object_id=notification.instance.object_id,
        )
        .values_list('created_by__email', flat=True)
    )


def _get_complaint_problem_created_by(notification):
    related_object = notification.instance.related_object
    if isinstance(related_object, Complaint):
        return [related_object.problem.created_by.email]
    return []


created_by_rcv = R(_get_created_by)
interviewers_rcv = R(_get_interviewers)
thread_participants_rcv = R(_get_thread_participants)
initiator_rcv = R(lambda x: [x.initiator.email])
complaint_problem_created_by_rcv = R(_get_complaint_problem_created_by)


class CommentNotification(FetchingNotificationBase):

    valid_related_classes = None

    def __init__(self, instance, initiator=None, **kwargs):
        if self.valid_related_classes is not None:
            assert isinstance(instance.related_object, self.valid_related_classes)
        super().__init__(instance, initiator, **kwargs)


class AssessmentCommentCreatedNotification(CommentNotification):

    subject_prefix = 'Комментарий к испытанию добавлен'
    template_name = 'email/comments/assessments/create.html'
    valid_related_classes = (Interview, Challenge)
    receivers = (
        created_by_rcv
        + interviewers_rcv
        + thread_participants_rcv
        - initiator_rcv
    )

    def get_subject(self):
        if isinstance(self.instance.related_object, Interview):
            return get_interview_email_subject(self.instance.related_object, self.subject_prefix)
        return get_candidate_email_subject(self.candidate, self.subject_prefix)

    def get_thread_id(self):
        return get_candidate_message_id(self.candidate)

    @property
    def candidate(self):
        return self.instance.related_object.candidate


class ComplaintCommentCreatedNotification(CommentNotification):

    subject_prefix = 'Комментарий к жалобе на задачу добавлен'
    template_name = 'email/comments/complaints/create.html'
    valid_related_classes = (Complaint,)
    receivers = (
        created_by_rcv
        + thread_participants_rcv
        + complaint_problem_created_by_rcv
        - initiator_rcv
    )

    def get_subject(self):
        return get_problem_email_subject(self.problem, self.subject_prefix)

    def get_thread_id(self):
        return get_problem_message_id(self.problem)

    @property
    def problem(self):
        return self.instance.related_object.problem


notification_classes = {
    Interview: AssessmentCommentCreatedNotification,
    Challenge: AssessmentCommentCreatedNotification,
    Complaint: ComplaintCommentCreatedNotification,
}


def notify_about_comment_create(instance, initiator, **kwargs):
    related_object_class = type(instance.related_object)
    notification_class = notification_classes.get(related_object_class)
    if not notification_class:
        raise KeyError(
            'Comment notification for class %s does not exist'
            % related_object_class
        )
    notification = notification_class(
        instance=instance,
        initiator=initiator,
        **kwargs
    )
    notification.send()
    return notification
