"""This module holds the tasks for the ``trainings`` app."""

from datetime import timedelta

from celery.utils.log import get_task_logger

from mtp.apps.accounts.models import Group, MTPUser
from mtp.celery import app

from .models import Training, TrainingSession

logger = get_task_logger(__name__)  # pylint: disable=invalid-name


@app.task
def duplicate_training_to_member(training_pk, new_state, params):
    """Task that will duplicate a training to a member defined in ``params``

    Parameters
    ----------
    new_state : string
        Value from ``VERSION_STATES`` to set to the ``version_state`` on the duplicated
        training,
    params : dict
        The fields to set on the training to duplicate. Must at least contain a ``owner_id``
        key.
        Values may represent primary keys of objects, not object themselves.

    Returns
    -------
    UUID or None
        The primary key of the new duplicated training, or ``None`` if the same duplicate is
        currently in progress.

    Notes
    -----
    This task simply convert primary keys to real objects and call the ``duplicate_to_member``
    method of the training.

    """

    training = Training.objects.get(pk=training_pk)

    # Converts PKs in params into real objects to pass to ``duplicate_to_member``
    params = params.copy()
    if 'owner_id' in params:
        params['owner'] = MTPUser.objects.get(pk=params.pop('owner_id'))
    if 'business_unit_id' in params:
        params['business_unit'] = Group.objects.get(pk=params.pop('business_unit_id'))

    try:
        new_training = training.duplicate_to_member(
            new_state=new_state,
            params=params,
            async=False,
            skip_in_progress=False,
        )
    except Training.DuplicateInProgress:
        return None

    return new_training.pk


@app.task
def create_training_draft(training_pk, fields=None):
    """Task that will create a new draft from a training

    Parameters
    ----------
    fields : dict, optional
        The fields to set on the new training. Could be empty.
        Values may represent primary keys of objects, not object themselves.

    Returns
    -------
    UUID or None
        The primary key of the new duplicated training, or ``None`` if the same draft creation is
        currently in progress.

    Notes
    -----
    This task simply call the ``create_draft`` method of the training.

    """

    training = Training.objects.get(pk=training_pk)

    # Converts PKs in params into real objects to pass to ``create_draft``
    fields = {} if not fields else fields.copy()
    if 'owner_id' in fields:
        fields['owner'] = MTPUser.objects.get(pk=fields.pop('owner_id'))

    try:
        new_training = training.create_draft(
            async=False,
            skip_in_progress=False,
            **fields
        )
    except Training.DuplicateInProgress:
        return None

    return new_training.pk


@app.task
def compute_assessment_scores(session_pk, force_recompute=True):
    """Task that will compute assessment scores of a session.

    Parameters
    ----------
    session_pk : UUID
        The primary key of the session we want to compute assessment scores.
    force_recompute : bool
        Set to False, to recompute only certifications and recommendations.
        Set to True, to recompute ``CompetencyTreeUserScore`` too and use new user activity scores.
        Default value is True.

    """

    session = TrainingSession.objects.get(pk=session_pk)
    session.compute_assessment_scores(force_recompute=force_recompute)


@app.task
def close_outdated_training_sessions(delta_after=timedelta()):
    """Task that will close the "outdated" ``TrainingSession`` instances

    Where "outdated" means the session got a ``end_date`` in the past,
    and a ``state`` to ``DURING``.

    Parameters
    ----------
    delta_after : timedelta
        It's a kind of a "grace period". It's allow closing the session not directly
        after they were played, but after a given amount of time.

    Returns
    -------
    list
        A list containing the UUID of the closed sessions

    Notes
    -----
    This task is called every day at midnight.

    """

    return TrainingSession.objects.close_outdated(delta_after=delta_after, async=True)
