#!/usr/bin/env python

"""tasksconverter: ...."""

__author__ = "Daniel Engvall"
__email__ = "daniel@engvalls.eu"

import dateparser
from datetime import timedelta, datetime
from loguru import logger
from typing import List, Dict, Union, Optional


def format_subject(subject: str, _type='outlook') -> str:
    """Properly format subject

    Args:
        subject:
        _type:

    Returns:

    """
    import re
    # Highlight keywords
    subject = re.sub(r'(@\w+\([^\]]+\))', '<b>\\1</b>', subject)
    return subject


def parse_category(category_list: List, _type='outlook') -> Dict:
    """Parse categories

    Args:
        category_list:
        _type:

    Returns:

    """
    import re

    if _type == 'outlook':
        rules = {r'client': r'\(([^\}]+)\)',
                 r'category': r'\{([^\}]+)\}'}
        result = {}
        for _type in rules.keys():
            result.update({_type: None})
        for category in category_list:
            for _type in rules.keys():
                match = re.search(rules[_type], category)
                if match:
                    result.update({_type: match.group(1)})
        return result


def convert_date_attribute(date: Union[datetime, str]) -> Optional[str]:
    """Converting date attribute

    Args:
        date:

    Returns:

    """
    import datetime
    if type(date) is datetime.datetime:
        out_date = date.strftime('%Y-%m-%d')
    elif date is None:
        out_date = None
    else:
        parsed_date = dateparser.parse(str(date))
        if parsed_date:
            out_date = parsed_date.strftime('%Y-%m-%d')
        else:
            out_date = None
    return out_date


def correct_task(input_dict: Dict) -> Union[str, Dict]:
    """Correcting the task

    Args:
        input_dict:

    Returns:

    """
    i = input_dict
    logger.debug(f'correcting dates in {input_dict}')
    # make sure there is a start date
    start_date = dateparser.parse(str(i.get('start_date', None)))
    close_date = dateparser.parse(str(i.get('close_date', None)))
    if any(((not start_date and close_date), (start_date and close_date and close_date <= start_date))):
        i['start_date'] = (dateparser.parse(i['close_date']) - timedelta(days=1)).strftime('%Y-%m-%d')
    return i


# noinspection PyUnboundLocalVariable,PyUnboundLocalVariable
def to_generic(tasks_list: List, _type='outlook') -> List:
    """Make list of tasks generic

    Args:
        tasks_list:
        _type:

    Returns:
        New list of generic tasks

    """
    generic_list = list()
    for task in tasks_list:
        if _type == 'outlook':
            logger.debug('converting outlook to generic')
            subject = format_subject(task['taskName'], _type='outlook')
            categories = task['taskCategories']
            categories = parse_category(categories, _type='outlook')
            client, category = categories['client'], categories['category']
            due_date = convert_date_attribute(task['due'])
            start_date = convert_date_attribute(task['startDate'])
            modified_date = convert_date_attribute(task['modifiedDate'])
            close_date = convert_date_attribute(task['completeDate'])
            if close_date:
                status = 'close'
            else:
                status = 'open'
        elif _type == 'jira':
            logger.debug('converting jira to generic')
            key = task.key
            subject = f'[{key}] {task.fields.summary}'
            client = task.fields.project.name
            category = None
            start_date = convert_date_attribute(task.fields.created)
            close_date = convert_date_attribute(task.fields.resolutiondate)
            modified_date = convert_date_attribute(task.fields.updated)
            due_date = convert_date_attribute(task.fields.duedate)
            status = 'open' if not any([_ in task.fields.status.name for _ in ('Done', 'Not in Scope')]) else 'close'
            # fix None dates
            if not close_date and status == 'close':
                close_date = modified_date
            if not due_date:
                due_date = modified_date
        elif _type == 'trello':
            logger.debug('converting trello to generic')
            key = task['project']
            subject = f'[{key}] {task["name"]}'
            client = ''
            category = None
            status = 'open' if task['closed'] is False else 'close'
            due_date = convert_date_attribute(task['due'])
            start_date = dateparser.parse(task['dateLastActivity']) - timedelta(days=5)
            if due_date:
                start_date = (dateparser.parse(task['due']) - timedelta(days=5)).strftime('%Y-%m-%d')
            else:
                start_date = start_date.strftime('%Y-%m-%d')
            if status == 'open':
                close_date = None
            else:
                close_date = convert_date_attribute(task['dateLastActivity'])
            modified_date = convert_date_attribute(task['dateLastActivity'])


            # fix None dates
            if not close_date and status == 'close':
                close_date = modified_date
            if not due_date:
                due_date = modified_date

        generic_task = {'subject': subject,
                        'client': client,
                        'category': category,
                        'start_date': start_date,
                        'close_date': close_date,
                        'due_date': due_date,
                        'modified_date': modified_date,
                        'status': status}
        generic_task = correct_task(generic_task)
        generic_list.append(generic_task)
    # sort the list
    generic_list = sorted(generic_list, key=lambda x: (str(x['client']), str(x['category']), str(x['status'])))
    logger.debug('complete converting to generic')
    return generic_list

