from staff.person.models import Staff

from staff.lib.utils.date import parse_date
from staff.trip_questionary.models import TripPurpose
from staff.trip_questionary.controller.context import get_departure_city
from staff.trip_questionary.controller.notifications import (
    NoticeNotification,
    TravelClosedNotification,
)
from staff.trip_questionary.controller.context import (
    make_cities_chain,
    get_issue_url,
)

from .base import OperationBase, lib


class SendEmailOperation(OperationBase):

    def run(self):
        notification_cls = self.get_notification_class()
        notification = self.get_notification(notification_cls)
        result = self.send_notification(notification)
        self.post_send(result)
        super(SendEmailOperation, self).run()
        return result

    def get_notification_class(self):
        return self.notification_class

    def get_notification(self, notification_class):
        params = self.get_notification_create_params()
        return notification_class(**params)

    def send_notification(self, notification):
        params = self.get_notification_send_params()
        return notification.send(**params)

    def get_main_recipient_email(self):
        return None

    def get_notification_send_params(self):

        recipients = [self.employee_data['employee'].work_email]

        main_recipient = self.get_main_recipient_email()
        if main_recipient:
            recipients.append(main_recipient)

        return {'recipients': recipients}

    def get_notification_create_params(self):
        return {
            'trip_uuid': self.trip.uuid,
            'context': self.get_notification_context()
        }

    def get_notification_context(self):
        ctx = self.trip.data.copy()
        ctx['cities_chain'] = make_cities_chain(self.trip.data)
        ctx['departure_city'] = get_departure_city(
            self.trip.data['city_list']
        )
        ctx['employee_data'] = self.employee_data.copy()
        return ctx

    def post_send(self, result):
        pass


def personalize(person_startrek_data, default=None):
    if not person_startrek_data:
        return default
    try:
        person = Staff.objects.get(login=person_startrek_data['id'])
    except (Staff.DoesNotExist, KeyError):
        person = default
    return person


@lib.register
class OnTripIssueCloseEmail(SendEmailOperation):
    def match_diff_preconditions(self):
        return (
            not self.TC.is_conf
            and
            not self.TC.is_new_employee
            and
            self.TC.is_employee_trip_ready(forced_event_type='trip')
            and
            self.TC.is_employee_just_trip_ready(forced_event_type='trip')
        )

    def match_preconditions(self):
        return (
            super(OnTripIssueCloseEmail, self).match_preconditions()
            or
            self.match_diff_preconditions()
        )

    notification_class = TravelClosedNotification

    def get_notification_context(self):
        context = super(OnTripIssueCloseEmail, self).get_notification_context()

        employee_data = context['employee_data']
        context['issue_url'] = get_issue_url(employee_data, 'trip_issue')
        context['closed_issue'] = employee_data['trip_issue']

        issue_fields = {
            'itinerary': 'cities_chain',
            'objective_description': 'objective',
            'hostCompany': 'receiver_side',
            'startDate': 'trip_date_from',
            'endDate': 'trip_date_to',
        }
        for issue_field, trip_field in issue_fields.items():
            if issue_field not in context['closed_issue']:
                context['closed_issue'][issue_field] = context[trip_field]

        context['closed_issue']['purpose'] = list(
            TripPurpose.objects
            .filter(id__in=context.get('purpose', []))
            .values('name', 'name_en')
        )

        date_template = '{0:%d.%m.%Y}'
        context['closed_issue']['startDate'] = date_template.format(context['closed_issue']['startDate'])
        context['closed_issue']['endDate'] = date_template.format(context['closed_issue']['endDate'])

        context['closed_issue']['employee'] = personalize(
            context['closed_issue'].get('employee'),
            default=context['employee_data']['employee']
        )
        context['closed_issue']['manager'] = personalize(
            context['closed_issue'].get('manager')
        )
        date_fields = [
            'beginDateCertificate',
            'endDateCertificate',
            'beginDateCertificateBack',
            'endDateCertificateBack'
        ]
        for date_field in date_fields:
            context['closed_issue'][date_field] = parse_date(
                context['closed_issue'].get(date_field)
            )

        return context

    def get_notification_send_params(self):

        component = self.employee_data['st_component']
        return {
            'recipients': [
                component.trip_money_email,
                component.hr_travel_email,
                component.mailing_list,
            ]
        }


# Дополнительно уведомляемые (interested_user_list)
@lib.register
class NoticeEmail(SendEmailOperation):
    def match_diff_preconditions(self):
        return (
            not self.TC.is_conf
            and
            self.TC.is_employee_interested_user_list
            and
            (
                (
                    self.TC.is_new_employee
                    and
                    (
                        self.TC.is_employee_approved
                        or
                        self.TC.is_employee_closed()
                    )
                )
                or
                (
                    not self.TC.is_new_employee
                    and
                    (
                        self.TC.is_employee_just_approved
                        or  # trip_info
                        self.TC.is_trip_info_changed
                        or  # cities_chain
                        self.TC.is_return_city_added
                        or  # trip_date_from, trip_date_to
                        self.TC.is_trip_dates_changed
                        or
                        self.TC.is_employee_interested_user_list_changed
                    )
                )
            )
        )

    def match_preconditions(self):
        return (
            super(NoticeEmail, self).match_preconditions()
            or
            self.match_diff_preconditions()
        )

    notification_class = NoticeNotification

    def get_notification_send_params(self):
        params = super(NoticeEmail, self).get_notification_send_params()

        recipients = params.get('recipients', [])
        recipients += [
            user['employee']
            for user in self.employee_data['interested_user_list']
        ]
        params['recipients'] = recipients
        return params
