from datetime import datetime, timedelta
from typing import List, Dict

from django.conf import settings
from django.http import JsonResponse

from staff.lib.mongodb import mongo
from staff.lib.requests import get_ids_repository
from staff.lib.utils.ordered_choices import OrderedChoices
from staff.gap.controllers.gap_tasks import GapTasks
from staff.gap.controllers.startrek import StartrekCtl
from staff.person.models import Staff


PROBLEM = OrderedChoices(
    ('ATTACHMENT', 'attached ticket[{issue_key}] to gap[{gap_id}]'),
    ('CREATION', 'there is no ticket for gap[{gap_id}]'),
    ('DATES', 'fixed dates for gap[{gap_id}] in ticket[{issue_key}]')
)


def update_master_issue(gap_id, issue_key):
    mongo.db['gaps'].update_one({'id': gap_id}, {'$set': {'master_issue': issue_key}})


def update_ticket_dates(issue_key, date_from, date_to):
    issue = StartrekCtl(issue_key=issue_key).issue
    if issue.status.key != 'closed':
        issue.update(start=date_from, end=date_to, ignore_version_change=True)


def filter_gaps_with_correct_organizations(gaps):
    st_fields = get_ids_repository(
        'startrek2',
        'fields',
        user_agent='Staff',
        oauth_token=settings.ROBOT_STAFF_OAUTH_TOKEN,
    )
    st_translation_ids = [int(x.id) for x in st_fields.get_one({'id': 'legalEntity2'})['optionsProvider']['values']]
    persons_with_correct_organization = set(
        Staff.objects
        .filter(
            id__in={gap['person_id'] for gap in gaps},
            organization__st_translation_id__in=st_translation_ids,
        )
        .values_list('id', flat=True)
    )
    return [gap for gap in gaps if gap['person_id'] in persons_with_correct_organization]


def get_gaps_without_ticket() -> List[str]:
    fix_release_datetime = datetime(2021, 9, 21, 17, 59, 0)

    all_gaps = list(mongo.db['gaps'].find({
        '$or': [{'master_issue': {'$exists': False}}, {'master_issue': None}],
        'workflow': {'$in': ['illness', 'vacation']},
        'state': {'$ne': 'canceled'},
        'created_at': {'$gte': fix_release_datetime},
        'modified_at': {'$lte': datetime.utcnow() - timedelta(minutes=30)},
    }))

    all_gaps = filter_gaps_with_correct_organizations(all_gaps)
    startrek_ctl = StartrekCtl()
    page_size = 30
    problems = []
    paginated_gaps = [all_gaps[i:i+page_size] for i in range(0, len(all_gaps), page_size)]
    for gaps in paginated_gaps:
        unique_keys = ['staff_gap_{}'.format(str(gap['_id'])) for gap in gaps]
        issue_by_id = {
            issue['unique'].rsplit('_')[-1]: issue
            for issue in startrek_ctl.find_by_unique(unique_keys)
        }

        for gap in gaps:
            issue = issue_by_id.get(str(gap['_id']), None)
            if issue:
                update_master_issue(gap['id'], issue['key'])
                problems.append(PROBLEM.ATTACHMENT.format(issue_key=issue['key'], gap_id=gap['id']))
            else:
                problems.append(PROBLEM.CREATION.format(gap_id=gap['id']))

    return problems


def get_gaps_with_bad_ticket_dates(hours: int) -> List[str]:
    gaps = list(mongo.db['gaps'].find({
        'master_issue': {'$exists': True},
        'workflow': 'vacation',
        'state': {'$ne': 'canceled'},
        'modified_at': {'$gte': datetime.utcnow() - timedelta(hours=hours)},
    }))

    issue_keys = [gap['master_issue'] for gap in gaps]
    issue_by_id = {
        issue['unique'].rsplit('_')[-1]: issue
        for issue in StartrekCtl().find_by_keys(issue_keys)
    }

    problems = []
    for gap in gaps:
        date_from = gap['date_from'].date().isoformat()
        date_to = gap['date_to'].date()
        if gap['full_day']:
            date_to = date_to - timedelta(days=1)
        date_to = date_to.isoformat()

        issue = issue_by_id[str(gap['_id'])]

        if issue.status.key != 'closed':
            if issue['start'] != date_from or issue['end'] != date_to:
                # update_ticket_dates(issue['key'], date_from, date_to)
                problems.append(PROBLEM.DATES.format(issue_key=issue['key'], gap_id=gap['id']))

    return problems


def check_gap_tickets(request):
    problems = get_gaps_without_ticket()

    if problems:
        return JsonResponse(data={'problems': problems})

    return JsonResponse(data={})


def dead_gap_tasks() -> Dict:
    failed = list(GapTasks.get_dead_tasks().order_by('id').values_list('id', flat=True))

    if failed:
        return {'failed_tasks': failed}

    return {}
