"""This module contains the ``create_or_update_fixtures`` command

This command is called when creating a new mtp instance or updating an existing one.
Therefore, it must only contains ``update`` / ``get_or_create`` statements.

"""

import os

from shutil import copyfile

from django.conf import settings
from django.core.exceptions import MultipleObjectsReturned
from django.core.management.base import BaseCommand, CommandError

from constance import config
from oauth2_provider.models import Application
from pinax.notifications.models import NoticeType
import waffle

from mtp.apps.accounts.constants import (
    GROUPTYPE_BUSINESS_LEVEL,
    GROUPTYPE_BUSINESS_TARGET,
    GROUPTYPE_BUSINESS_TYPE,
    GROUPTYPE_BUSINESS_UNIT,
    GROUPTYPE_BUSINESS_ZONE,
    GROUPTYPE_INTERNAL,
    GROUPTYPE_JOB_NAME,
    GROUPTYPE_JOB_PROFILE,
    GROUPTYPE_JOB_TYPE,
    INTERNAL_GROUP_TRAINEE,
    INTERNAL_GROUP_TRAINER,
    INTERNAL_GROUP_WHOSWHO,
)
from mtp.apps.accounts.models import Group, GroupType, MTPUser
from mtp.apps.accounts.utils import init_user
from mtp.apps.reveal.api.constants import (
    DEFAULT_REVEAL_BACKGROUND_PATH,
    DEFAULT_REVEAL_WELCOM_PATH
)
from mtp.apps.themes.constants import (
    DEFAULT_THEME_NAME,
    DEFAULT_THEME_BACKGROUND_PATH,
    DEFAULT_THEME_BACKGROUND_DIFFUSION_PATH,
    DEFAULT_THEME_HEADER_PATH,
    DEFAULT_HOME_DIFFUSION_PATH,
    DEFAULT_FAVICON_PATH,
    DEFAULT_BRAND_LOGO_PATH,
    DEFAULT_REVEAL_LOGO_PATH
)

from mtp.apps.themes.models import Theme

DEFAULT_PASSWORD = '123456'


def create_group(name, type_name):
    """Try to create a new ``Group`` with the provided params

    Parameters
    ----------
    name: str
        The group name
    type_name: str
        The group type name

    """

    group_type, __ = GroupType.objects.get_or_create(name=type_name)
    __, created = Group.objects.get_or_create(name=name, type=group_type)
    if created:
        print("Creating group: '%s'." % name)
    else:
        print("Group '%s' already exists, skipping." % name)


def create_user(username, first_name, last_name, email, is_trainer):
    """Try to create a new ``MTPUser`` with the provided params

    Parameters
    ----------
    username: str
        The username of the user
    first_name: str
        The first name of the user
    last_name: str
        The last name of the user
    email: str
        The email of the user
    is_trainer: bool
        If True, the user will be a trainer,
        If False, the user will be a trainee

    """

    user, created = MTPUser.objects.get_or_create(
        username=username,
        defaults={
            'first_name': first_name,
            'last_name': last_name,
            'email': email,
        }
    )
    if created:
        init_user(user, DEFAULT_PASSWORD, None, is_trainer)
        if is_trainer:
            print("Creating trainer: '%s'." % username)
        else:
            print("Creating trainee: '%s'." % username)
    else:
        if user.is_staff:
            print("User '%s' already exists, and is a trainer." % username)
        else:
            print("User '%s' already exists, and is a trainee." % username)


def update_default_media(media):
    """ Copy default media in media root instance

    Parameters
    ----------
    media: str
        The relative path of the default media we want to update
    """

    print("Default media : copying : %s" % media)
    src_media = os.path.join(settings.PROJECT_ROOT, 'media', media)
    dest_media = os.path.join(settings.MEDIA_ROOT, media)

    # Test if default media root not already exist
    dest_default_media_root = os.path.join(settings.MEDIA_ROOT, 'default')
    if not os.path.exists(dest_default_media_root):
        os.makedirs(dest_default_media_root)

    try:
        copyfile(src_media, dest_media)
    except OSError as exception:
        print(exception)
        raise CommandError(
            "Default media error: cannot copy %s to %s", src_media, dest_media
        )
    print("Default media : %s is updated" % media)


class Command(BaseCommand):
    """This command create/update some mandatory fixtures"""

    args = ''
    help = "Populate the MTP database with generic initial data."

    def handle(self, *args, **options):
        if settings.INSTANCE_IS_SLAVE:
            raise CommandError(
                "A local server can't initialize data, please check the configuration."
            )

        # Create initial groups and group types.
        GroupType.objects.get_or_create(name=GROUPTYPE_BUSINESS_LEVEL)
        GroupType.objects.get_or_create(name=GROUPTYPE_BUSINESS_TARGET)
        GroupType.objects.get_or_create(name=GROUPTYPE_BUSINESS_TYPE)
        GroupType.objects.get_or_create(name=GROUPTYPE_BUSINESS_UNIT)
        GroupType.objects.get_or_create(name=GROUPTYPE_BUSINESS_ZONE)
        GroupType.objects.get_or_create(name=GROUPTYPE_JOB_NAME)
        GroupType.objects.get_or_create(name=GROUPTYPE_JOB_PROFILE)
        GroupType.objects.get_or_create(name=GROUPTYPE_JOB_TYPE)
        create_group(INTERNAL_GROUP_TRAINER, GROUPTYPE_INTERNAL)
        create_group(INTERNAL_GROUP_TRAINEE, GROUPTYPE_INTERNAL)
        create_group(INTERNAL_GROUP_WHOSWHO, GROUPTYPE_INTERNAL)

        # Create the default theme.
        default_theme = {
            'default': True,

            'color_first': "#823481",
            'color_second': "#d7d7d7",
            'color_item': "#ffffff",
            'color_selected_item': "#823481",
            'color_text_item': "#686868",
            'color_text_selected_item': "#ffffff",
            'color_text_quizz': "#ffffff",

            'background_color': "#f3f3f3",
            'background_color_diffusion': "#f3f3f3",

            'main': "#6b32bf",
            'main_lighter': "#b29dd2",
            'main_darker': "#2b134e",
            'complementary': "#45a49a",
            'clear': "#ffffff",
            'background': "#f3f3f3",

            'gray': "#d3d3d3",
            'gray_lighter': "#ededed",
            'gray_darker': "#505050",

            'text_on_main': "#ffffff",
            'text_on_main_lighter': "#000000",
            'text_on_main_darker': "#ffffff",
            'text_on_complementary': "#ffffff",
            'text_on_clear': "#000000",

            'accent_blue': "#7dd6da",
            'accent_green': "#a5de4f",
            'accent_yellow': "#fed201",
            'accent_pink': "#f56dc1",
            'accent_red': "#f26037",
            'accent_white': "#ffffff",

            'font_name': "HelveticaNeue",
            'font_bold_name': "HelveticaNeue-Bold",
            'font_thin_name': "HelveticaNeue-Light",
        }

        try:
            __, created = Theme.objects.get_or_create(
                name=DEFAULT_THEME_NAME, defaults=default_theme
            )
        except MultipleObjectsReturned:
            created = False

        if created:
            print("Creating default theme.")
        else:
            print("Default theme already exists.")

        # Create the initial Waffle feature switches
        print("Creating Waffle feature switches.")
        waffle.models.Switch.objects.get_or_create(
            name='enable_assessments',
            defaults={'active': False}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_photostory',
            defaults={'active': True}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_evaluation',
            defaults={'active': True}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_training_locks',
            defaults={'active': False}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_roleplay',
            defaults={'active': False}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_translation',
            defaults={'active': False}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_likes',
            defaults={'active': True}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_surveys',
            defaults={'active': False}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_sessions_end_mail_for_trainees',
            defaults={'active': True}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_sessions_end_mail_for_trainers',
            defaults={'active': True}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_user_welcome_mail',
            defaults={'active': True}
        )
        waffle.models.Switch.objects.get_or_create(
            name='enable_duplicate_training_mail',
            defaults={'active': True}
        )

        # Notice types

        print("Creating Notice types.")

        NoticeType.create(
            "trainee_post_trainingsession",
            "Session content online",
            "Send to the trainee at the end of a training session"
        )
        NoticeType.create(
            "trainer_post_trainingsession",
            "Session content online",
            "Send to the trainer at the end of a training session"
        )
        NoticeType.create(
            "user_welcome",
            "Welcoming the user",
            "Send when a new user is registered across the system"
        )
        NoticeType.create(
            "new_available_training",
            "New training available for the user",
            "Send when a training is duplicate to a user"
        )

        if config.SABA_ENABLED:
            NoticeType.create(
                "saba_results",
                "Saba recap email",
                "Send after assessments results are sent to Saba"
            )

        # Magency admin user

        print("Creating magency admin user")

        admin_user, __ = MTPUser.objects.get_or_create(
            username=settings.MAGENCY_ADMIN_USERNAME,
            is_superuser=True,
            is_staff=True,
        )
        admin_user.set_password(settings.MAGENCY_ADMIN_PASSWORD)
        admin_user.save()

        # Oauth application

        print("Creating Oauth client application")

        # HTML Client Application
        Application.objects.get_or_create(
            client_id=settings.OAUTH_APPLICATION_CLIENT_ID,
            defaults={
                'client_secret': settings.OAUTH_APPLICATION_CLIENT_SECRET,
                'user': admin_user,
                'client_type': Application.CLIENT_CONFIDENTIAL,
                'authorization_grant_type': Application.GRANT_PASSWORD,
                'name': settings.OAUTH_APPLICATION_NAME
            }
        )

        # CAST Client Application
        Application.objects.get_or_create(
            client_id=settings.OAUTH_CAST_APPLICATION_CLIENT_ID,
            defaults={
                'client_secret': settings.OAUTH_CAST_APPLICATION_CLIENT_SECRET,
                'user': admin_user,
                'client_type': Application.CLIENT_CONFIDENTIAL,
                'authorization_grant_type': Application.GRANT_CLIENT_CREDENTIALS,
                'name': settings.OAUTH_CAST_APPLICATION_NAME
            }
        )

        # Default Media
        # As we can not have a `create_or_update_fixtures` command by app
        # (django-admin stop after the first command execution, in the apps sorted by name A->Z)
        # So we write this here, but it is not its place
        # Furthermore, the update of default media will be added in the deployement script
        # in its next version.
        # @todo Remove this part of update at the next version of deployement script

        print("Updating default media")

        medias = [
            DEFAULT_THEME_BACKGROUND_PATH,
            DEFAULT_THEME_BACKGROUND_DIFFUSION_PATH,
            DEFAULT_THEME_HEADER_PATH,
            DEFAULT_HOME_DIFFUSION_PATH,
            DEFAULT_FAVICON_PATH,
            DEFAULT_BRAND_LOGO_PATH,
            DEFAULT_REVEAL_LOGO_PATH,
            DEFAULT_REVEAL_BACKGROUND_PATH,
            DEFAULT_REVEAL_WELCOM_PATH
        ]

        for media in medias:
            update_default_media(media)


        print("All done.")
