from datetime import datetime, timedelta

from staff.gap.workflows.registry import library as gap_workflows

from staff.trip_questionary.controller.context import make_cities_chain
from staff.trip_questionary.models import EVENT_TYPE

from .base import OperationBase, lib


class GapOperation(OperationBase):
    """Базовый класс операций GAP"""

    @property
    def workflow_cls(self):
        gap_workflows_map = {
            EVENT_TYPE.TRIP: gap_workflows.get('TripWorkflow'),
            EVENT_TYPE.TRIP_CONF: gap_workflows.get('ConferenceTripWorkflow'),
            EVENT_TYPE.CONF: gap_workflows.get('ConferenceWorkflow'),
        }
        return gap_workflows_map[self.trip.data['event_type']]

    def get_date_from(self):
        if (self.employee_data.get('departure_date') and
                self.employee_data.get('custom_dates')):
            _date = self.employee_data['departure_date']
        elif self.trip.data.get('trip_date_from'):
            _date = self.trip.data['trip_date_from']
        else:
            _date = self.trip.data['event_date_from']

        return datetime.combine(_date, datetime.min.time())

    def get_date_to(self):
        if (self.employee_data.get('return_date') and
                self.employee_data.get('custom_dates')):
            _date = self.employee_data['return_date']
        elif self.trip.data.get('trip_date_to'):
            _date = self.trip.data['trip_date_to']
        else:
            _date = self.trip.data['event_date_to']
        _date += timedelta(days=1)
        return datetime.combine(_date, datetime.min.time())

    def get_comment(self):
        if self.TC.is_conf or self.TC.is_private:
            return ''
        else:
            cities = make_cities_chain(self.trip.data)
            return '{cities}\n{info}'.format(
                info=self.employee_data['trip_info'],
                cities=cities
            )

    def get_event_type(self):
        return 'conf' if self.TC.is_conf else 'trip'

    def get_master_issue(self):
        return self.trip.data[self.get_event_type() + '_issue']['key']

    def get_slave_issues(self):
        return [self.employee_data[self.get_event_type() + '_issue']['key']]

    def get_gap(self):
        return self.employee_data['gap']

    def set_gap(self):
        self.employee_data['gap'] = {
            'id': self.workflow.gap['id'],
            'state': self.workflow.gap['state'],
        }


class EditGap(GapOperation):
    def run(self):
        self.workflow = self.workflow_cls.init_to_modify(
            modifier_id=self.trip.data['author'].id,
            gap_id=self.get_gap()['id'],
        )
        self.wf_action()
        self.set_gap()
        super(EditGap, self).run()

    def wf_action(self):
        raise NotImplementedError('Class is too abstract')


@lib.register
class CreateGap(GapOperation):
    "Создание трипа в гэпе"
    def match_preconditions(self):
        return (
            (
                (
                    not self.TC.is_conf
                    and
                    self.TC.is_trip_toplevel_issue_created
                    and
                    self.TC.is_trip_employee_issue_created
                )
                or
                (
                    self.TC.is_conf
                    and
                    self.TC.is_conf_toplevel_issue_created
                    and
                    self.TC.is_conf_employee_issue_created
                )
            )
            and
            not self.TC.is_gap_created
            and
            not self.TC.is_employee_canceled
        )

    def run(self):
        self.workflow = self.workflow_cls.init_to_new(
            modifier_id=self.trip.data['author'].id,
            person_id=self.employee_data['employee'].id,
        )
        self.workflow.tq_add_gap(self.get_gap_data())
        self.set_gap()
        super(CreateGap, self).run()

    def get_gap_data(self):
        return {
            # сейчас тут даты без времени и тз не нужны, но, переделывая, надо не забыть
            'date_from': self.get_date_from(),
            'date_to': self.get_date_to(),

            'comment': self.get_comment(),
            'master_issue': self.get_master_issue(),
            'slave_issues': self.get_slave_issues(),
            'form_key': self.trip.uuid,
        }


@lib.register
class UpdateEditGap(EditGap):
    """Обновление данных в GAP"""
    def match_diff_preconditions(self):
        return (
            self.TC.is_gap_created
            and
            (
                (
                    not self.TC.is_conf
                    and
                    (
                        self.TC.is_return_city_added
                        or
                        self.TC.is_trip_dates_changed
                        or
                        self.TC.is_employee_departure_date_changed
                        or
                        self.TC.is_employee_return_date_changed
                        or
                        self.TC.is_trip_info_changed
                    )

                )
                or
                (
                    self.TC.is_conf
                    and
                    self.TC.is_event_dates_changed
                )
            )
        )

    def get_gap_data(self):
        return {
            'date_from': self.get_date_from(),
            'date_to': self.get_date_to(),
            'comment': self.get_comment(),
        }

    def wf_action(self):
        self.workflow.tq_edit_gap(self.get_gap_data())


@lib.register
class ConfirmEditGap(EditGap):
    """
    При утверждении тикета в Стартреке
    перевести Gap в стейт confirm
    """
    def match_preconditions(self):
        return (
            self.TC.is_gap_created
            and
            not self.TC.is_gap_approved
            and
            (
                self.TC.is_employee_approved
                or
                self.TC.is_employee_trip_ready()
                or
                self.TC.is_employee_hr_ready()
                or
                self.TC.is_employee_check_in
                or
                self.TC.is_employee_closed()
            )
        )

    def wf_action(self):
        self.workflow.tq_confirm_gap()


@lib.register
class CancelEditGap(EditGap):
    """
    Когда тикет по сотруднику переходит в статус «Закрыт»
    с резолюцией «Не будет исправлено», командировку в гэпе надо отменять.
    """
    def match_preconditions(self):
        return (
            self.TC.is_gap_created
            and
            (
                (
                    not self.TC.is_conf
                    and
                    self.TC.is_trip_toplevel_issue_created
                    and
                    self.TC.is_trip_employee_issue_created
                )
                or
                (
                    self.TC.is_conf
                    and
                    self.TC.is_conf_toplevel_issue_created
                    and
                    self.TC.is_conf_employee_issue_created
                )
            )
            and
            not self.TC.is_gap_canceled
            and
            self.TC.is_employee_canceled
        )

    def wf_action(self):
        self.workflow.tq_cancel_gap()


@lib.register
class RenewEditGap(EditGap):
    """
    Когда тикет по сотруднику переоткрыт
    отсутствие надо реанимировать.
    """
    def match_preconditions(self):
        return (
            self.TC.is_gap_created
            and
            (
                (
                    not self.TC.is_conf
                    and
                    self.TC.is_trip_toplevel_issue_created
                    and
                    self.TC.is_trip_employee_issue_created
                )
                or
                (
                    self.TC.is_conf
                    and
                    self.TC.is_conf_toplevel_issue_created
                    and
                    self.TC.is_conf_employee_issue_created
                )
            )
            and
            not self.TC.is_gap_new
            and
            self.TC.is_employee_open
        )

    def wf_action(self):
        self.workflow.tq_renew_gap()
