"""This module contains the utils for the ``evaluations`` app"""

import io

from django.conf import settings
from django.db.models import Avg

from mtp.apps.common import xls

from .models import Criterion, Evaluation, Rating


def export_evaluation_stat_raw(session):  # pylint: disable=too-many-branches,too-many-locals
    """Export the workshops statistics for a given training session

    Parameters
    ----------
    session: ``mtp.apps.trainings.models.TrainingSession`` instance
        The session we want to compute the statistics for

    Returns
    -------
    sheets: list

    """

    training = session.training
    evaluations = Evaluation.objects.non_deleted().for_training(training)
    session_users = session.users.non_deleted().order_by(
        'last_name', 'first_name'
    )

    evaluations_types = Evaluation.EVALUATION_TYPES

    sheets = []
    for evaluation in evaluations:

        evaluator = (evaluation.evaluation_type in [evaluations_types.MAY_EVALUATE_OTHERS,
                                                    evaluations_types.MAY_EVALUATE_ALL])
        auto_evaluator = (evaluation.evaluation_type in [evaluations_types.MAY_EVALUATE_SELF,
                                                         evaluations_types.MAY_EVALUATE_ALL])

        lines_auto = []
        lines_group = []
        exercise_name_line = [('', 'EMPTY'), ('', 'EMPTY')]
        criteria_name_line = [
            ('First name', 'NAMES_HEADER_STYLE'),
            ('Last name', 'NAMES_HEADER_STYLE')
        ]
        users_lines_auto = {}
        users_lines_group = {}
        average_line_auto = [('', 'EMPTY'), ('Average', 'TERTIARY_HEADER')]
        average_line_auto_count = [('', 'EMPTY'), ('Participation', 'TERTIARY_HEADER')]
        average_line_group = [('', 'EMPTY'), ('Average', 'TERTIARY_HEADER')]
        average_line_group_count = [('', 'EMPTY'), ('Participation', 'TERTIARY_HEADER')]

        for user in session_users:

            if evaluator:
                users_lines_group[user.username] = [
                    ('%s' % user.first_name, 'NAMES_STYLE'),
                    ('%s' % user.last_name, 'NAMES_STYLE')
                ]

            if auto_evaluator:
                users_lines_auto[user.username] = [
                    ('%s' % user.first_name, 'NAMES_STYLE'),
                    ('%s' % user.last_name, 'NAMES_STYLE')
                ]

        for exercise in evaluation.exercises.non_deleted().order_by('sort_order'):

            exercise_name_line.append((exercise.name, 'PRIMARY_HEADER'))
            criteria_name_line.append(('', 'PRIMARY_HEADER'))
            average_line_auto.append(('', 'PRIMARY_HEADER'))
            average_line_auto_count.append(('', 'PRIMARY_HEADER'))
            average_line_group.append(('', 'PRIMARY_HEADER'))
            average_line_group_count.append(('', 'PRIMARY_HEADER'))

            for user in session_users:
                if evaluator:
                    users_lines_group[user.username].append(('', 'PRIMARY_HEADER'))
                if auto_evaluator:
                    users_lines_auto[user.username].append(('', 'PRIMARY_HEADER'))

            for num_crit in exercise.criteria.non_deleted().filter(
                    criterion_type=Criterion.CRITERION_TYPES.QUANTITATIVE):
                exercise_name_line.append(('', 'EMPTY'))
                criteria_name_line.append((num_crit.description, 'SECONDARY_HEADER'))
                average_auto = 0.0
                average_auto_count = 0
                average_group = 0.0
                average_group_count = 0

                for user in session_users:
                    if auto_evaluator:
                        auto_value = Rating.objects.filter(
                            criterion=num_crit,
                            judge=user,
                            trainee=user,
                            session=session
                        ).aggregate(
                            Avg('score')
                        )['score__avg']

                        if auto_value:
                            average_auto += auto_value
                            average_auto_count += 1

                        users_lines_auto[user.username].append((auto_value, 'DEFAULT'))

                    # group average
                    if evaluator:
                        group_value = Rating.objects.filter(
                            criterion=num_crit,
                            trainee=user,
                            session=session
                        ).exclude(
                            judge=user
                        ).aggregate(
                            Avg('score')
                        )['score__avg']

                        if group_value:
                            average_group += group_value
                            average_group_count += 1

                        users_lines_group[user.username].append((group_value, 'DEFAULT'))

                if average_auto_count != 0:
                    average_auto = average_auto / average_auto_count

                if average_group_count != 0:
                    average_group = average_group / average_group_count

                average_line_auto.append((average_auto, 'DEFAULT'))
                average_line_auto_count.append((average_auto_count, 'DEFAULT'))

                average_line_group.append((average_group, 'DEFAULT'))
                average_line_group_count.append((average_group_count, 'DEFAULT'))

            for num_verb in exercise.criteria.non_deleted().filter(
                    criterion_type=Criterion.CRITERION_TYPES.QUALITATIVE):
                exercise_name_line.append(('', 'EMPTY'))
                criteria_name_line.append((num_verb.description, 'SECONDARY_HEADER'))
                for user in session_users:

                    if auto_evaluator:

                        auto_comments = ''
                        for comment in Rating.objects.filter(judge=user,
                                                             trainee=user,
                                                             session=session,
                                                             criterion=num_verb):
                            auto_comments = auto_comments + '\n+ ' + comment.text

                        users_lines_auto[user.username].append((auto_comments, 'DEFAULT'))

                    if evaluator:

                        group_comments = ''
                        for comment in Rating.objects.filter(
                                criterion=num_verb,
                                trainee=user,
                                session=session
                        ).exclude(
                            judge=user
                        ):
                            group_comments = group_comments + '\n+ ' + comment.text

                        users_lines_group[user.username].append((group_comments, 'DEFAULT'))

                average_line_auto.append(('', 'DEFAULT'))
                average_line_auto_count.append(('', 'DEFAULT'))
                average_line_group.append(('', 'DEFAULT'))
                average_line_group_count.append(('', 'DEFAULT'))

        if auto_evaluator:
            lines_auto.append(exercise_name_line)
            lines_auto.append(criteria_name_line)

            for user in session_users:
                lines_auto.append(users_lines_auto[user.username])

            lines_auto.append(average_line_auto)
            lines_auto.append(average_line_auto_count)
            evaluation_name = 'auto-%s' % (evaluation.name)
            sheets.append((evaluation_name, lines_auto))

        if evaluator:
            lines_group.append(exercise_name_line)
            lines_group.append(criteria_name_line)

            for user in session_users:
                lines_group.append(users_lines_group[user.username])

            lines_group.append(average_line_group)
            lines_group.append(average_line_group_count)
            evaluation_name = 'group-%s' % (evaluation.name)
            sheets.append((evaluation_name, lines_group))

    return sheets


def export_evaluation_stat_xls(session):
    """Build an xlsx file containing the workshops stats of a given training session

    Parameters
    ----------
    session: ``mtp.apps.trainings.models.TrainingSession`` instance
        The session we want to build the file for

    Returns
    -------
    xls_file: ``XLSWriter`` instance

    """

    sheets = export_evaluation_stat_raw(session)

    xls_file = io.BytesIO()
    xls_writer = xls.XLSWriter(xls_file, logo=settings.NORMAL_CLIENT_LOGO)

    for sheet_name, sheet_content in sheets:
        name = xls_writer.add_sheet(sheet_name)
        xls_writer.writerows(sheet_content, name)

    xls_writer.save()

    return xls_file
