# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
import logging
from startrek_client import Startrek
from time import sleep
import traceback as tb

from errs import AssigneeError, LeadError
from robot import CONFIG, SECRET
from utils import get_from_date, is_stopped, make_request, notify, parse_st_datetime, send_mail

logger = logging.getLogger(__name__)


def check_queue(debug=False):
    issues = []
    try:
        st_client = Startrek(useragent='', token=SECRET['token'])
        st_query = CONFIG['st_query'].format(get_from_date(8), get_from_date())
        logger.info(u'Use st_query:\n%s', st_query.replace('\n', ' '))

        for issue in st_client.issues.find(st_query, order=['+resolved']):
            parent_issue = get_parent_issue(debug, st_client, issue)
            if parent_issue not in issues and is_stopped(parent_issue):
                issues.append(parent_issue)

    except Exception:
        logger.exception('Oops!')
        if not debug:
            send_mail(to=['leroy@yandex-team.ru', ], subject=u'Что-то сломалось!',
                      message=u'Ошибка:\n{}'.format(tb.format_exc()))
    finally:
        logger.info('%i issues in queue', len(issues))
        return issues


def get_parent_issue(debug, st_client, issue):
    while issue.parent:
        try:
            issue = st_client.issues[issue.parent.key]
        except Exception:
            logger.warning('%s: access to the parent %s denied', issue.key, issue.parent.key)
            notify(debug, issue, 'parent_issue', parent_issue_key=issue.parent.key, issue_key=issue.key,
                   st_url=CONFIG['st_url'])
            return issue

    return issue


def task_worker(task):
    logger.debug('%s: start task_worker', task.issue.key)
    try:
        while is_stopped(task.issue):
            if task.time_left is None:
                logger.debug('%s: time_left is None', task.issue.key)
                return task

            else:
                logger.debug('{}: {} < 0 {}'.format(task.issue.key, task.time_left, task.time_left <= 0))
                if task.time_left > 0:
                    timeout = task.get_timeout()
                    logger.info('%s: check status in %s', task.issue.key, str(timedelta(seconds=round(timeout))))
                    sleep(timeout)

                    task.time_left = task.check_time_left()

                elif task.time_left <= 0:
                    logger.debug('%s: request_fb', task.issue.key)
                    task.request_fb()
                    break

    except Exception:
        logger.exception('%s: Oops!', task.issue.key)
        if not task.debug:
            send_mail(to=['leroy@yandex-team.ru', ], subject=u'Что-то сломалось!',
                      message=u'{}\{}\nОшибка:\n{}'.format(CONFIG['st_url'], task.issue.key, tb.format_exc()))
    finally:
        return task


class FBTask(object):
    def __init__(self, debug=False, issue=None):
        super(FBTask, self).__init__()
        try:
            logger.debug('%s: init FBTask', issue.key)
            self.debug, self.issue = debug, issue
            self.people = get_people(issue)

            self.delay_time = 60 * 60 * 24 if self.issue.queue.key == 'YANPARTNERS' else 60 * 60 * 24 * 7
            self.time_left = self.check_time_left()
            logger.debug('%s: FBTask initialized', issue.key)

        except AssigneeError as exc:
            logger.error(exc.message)
            notify(self.debug, self.issue, 'assignee', issue_key=self.issue.key, followers=CONFIG['owner'],
                   st_url=CONFIG['st_url'])
            raise exc

        except LeadError as exc:
            logger.error(exc.message)
            notify(self.debug, self.issue, 'lead', lead=exc.lead, leads=', '.join(CONFIG['leads']),
                   issue_key=self.issue.key, followers=CONFIG['owner'], st_url=CONFIG['st_url'])
            raise exc

        except Exception as exc:
            logger.exception('%s: Oops!', issue.key)
            if not debug:
                send_mail(to=['leroy@yandex-team.ru', ], subject=u'{}: Что-то сломалось!'.format(issue.key),
                          message=u'Ошибка:\n{}'.format(tb.format_exc()))
            raise exc

    def check_time_left(self):
        comments = list(self.issue.comments)
        if comments:
            if comments[-1].createdBy.login == SECRET['PASSPORT']['login']:
                logger.info('%s: last comment from %s', self.issue.key, SECRET['PASSPORT']['login'])
                return None

        robot_comments = [comment for comment in comments if comment.createdBy.login == SECRET['PASSPORT']['login']]
        last_request_date = parse_st_datetime(comments[-1].createdAt) if robot_comments else None

        closed_log = []
        for change_ in [change_ for change_ in self.issue.changelog
                        if change_.type == 'IssueWorkflow' and change_.fields]:
            if last_request_date is None or parse_st_datetime(change_.updatedAt) >= last_request_date:
                closed = [
                    field for field in change_.fields if
                    (field['field'].id == 'status' and getattr(field['to'], 'key', None) in ['closed', 'resolved'])
                    or (field['field'].id == 'resolution' and getattr(field['to'], 'key', None) == 'fixed')
                ]
                if closed:
                    closed_log.append(change_)
        if len(closed_log) == 0:
            if last_request_date is not None:
                logger.info(
                    '{}: no transitions after last request {:%Y-%m-%d %H:%M}'.format(self.issue.key, last_request_date))
            return None

        closed_at = parse_st_datetime(closed_log[-1].updatedAt)
        if closed_at.day == 5:
            closed_at = closed_at - relativedelta(days=1)
        elif closed_at.day == 6:
            closed_at = closed_at - relativedelta(days=2)
        delta = datetime.now() - closed_at
        time_left = self.delay_time - delta.total_seconds()

        logger.info('%s: %s left', self.issue.key, str(timedelta(seconds=round(time_left))))
        return time_left

    def get_timeout(self):
        if self.issue.queue.key == 'YANPARTNERS':
            return self.time_left / 4
        else:
            return self.time_left / 24

    def request_fb(self):
        if not self.debug:
            logger.info('%s: request feedback', self.issue.key)
            self.issue.comments.create(text=self._get_fb_text(), summonees=[self.issue.createdBy.login])
        else:
            logger.info(u'{}: request feedback\n{}'.format(self.issue.key, self._get_fb_text()))

    def _get_fb_text(self):
        fb_url = unicode(CONFIG['url']).format(
            issue_url='{}/{}'.format(CONFIG['st_url'], self.issue.key),
            first_name=self.people['assignee_fname'].replace(' ', '%20'),
            last_name=self.people['assignee_lname'].replace(' ', '%20'))

        return CONFIG['comment'].format(fb_url=fb_url, lead=self.people['lead'])


def get_people(issue):
    first_name, last_name = get_assignee_name(issue)
    lead = get_lead(issue)
    return {'assignee_fname': first_name, 'assignee_lname': last_name, 'lead': lead}


def get_assignee_name(issue):
    if issue.assignee is None:
        raise AssigneeError('%s: assignee is None' % issue.key)

    if getattr(issue.assignee, 'login') == issue.createdBy.login:
        raise AssigneeError('%s: issue created by assignee' % issue.key)

    return getattr(issue.assignee, 'firstName', ''), getattr(issue.assignee, 'lastName', '')


def get_lead(issue):
    fields = ['department_group.department.heads.person.login',
              'department_group.ancestors.department.heads.person.login']
    url_params = 'persons?login={login}&_one=1&_fields={fields}'.format(login=getattr(issue.assignee, 'login'),
                                                                        fields=','.join(fields))
    response = make_request(url='{}/{}'.format(CONFIG['staff_url'], url_params),
                            headers={'Authorization': 'OAuth %s' % SECRET['token']}, timeout=60)

    try:
        lead = response['department_group']['department']['heads'].pop()
        lead = lead['person']['login']
    except IndexError:
        lead = 'olesya'

    if lead == 'olesya':
        return CONFIG['fb_lead']
    elif lead in CONFIG['leads']:
        return lead

    heads = response['department_group']['ancestors']
    try:
        lead = heads.pop()['department']['heads'].pop()['person']['login']
    except IndexError:
        return CONFIG['fb_lead']

    if lead not in CONFIG['leads']:
        raise LeadError('%s: unknown lead %s' % (issue.key, lead), lead=lead)
    else:
        return lead
