""" Common views for the registry dashboard
"""
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from django.urls import reverse_lazy

import core_curate_app.components.curate_data_structure.api as curate_data_structure_api
from core_dashboard_common_app import constants as dashboard_common_constants
from core_dashboard_common_app import settings
from core_dashboard_common_app.views.common.forms import ActionForm, UserForm
from core_dashboard_common_app.views.common.views import DashboardRecords, DashboardForms
from core_dashboard_common_app.views.common.views import DashboardWorkspaceRecords
from core_dashboard_registry_app import constants as dashboard_constants
from core_dashboard_registry_app.settings import INSTALLED_APPS
from core_dashboard_registry_app.utils.query.mongo.prepare import create_query_dashboard_resources
from core_dashboard_registry_app.views.common.ajax import EditDataView
from core_main_app.access_control.exceptions import AccessControlError
from core_main_app.commons import exceptions as exceptions
from core_main_app.components.data import api as data_api
from core_main_app.components.user import api as user_api
from core_main_app.components.user.api import get_id_username_dict
from core_main_app.components.workspace.api import check_if_workspace_can_be_changed
from core_main_app.utils.pagination.django_paginator.results_paginator import ResultsPaginator
from core_main_app.utils.rendering import render
from core_main_registry_app.commons.constants import DataStatus
from core_main_registry_app.components.custom_resource import api as custom_resource_api
from core_main_registry_app.components.data.api import get_status, get_role
from core_main_registry_app.constants import CUSTOM_RESOURCE_TYPE

if 'core_curate_registry_app' in INSTALLED_APPS:
    import core_curate_registry_app.components.curate_data_structure.api as \
        curate_data_structure_registry_api


@login_required(login_url=reverse_lazy("core_main_app_login"))
def home(request):
    """ Home page.

    Args:
        request:

    Returns:
    """

    context = {}
    if 'core_curate_app' in INSTALLED_APPS:
        context.update({'draft': True})

    assets = {
        "css": ['core_dashboard_registry_app/user/css/home.css'],
    }

    return render(request, dashboard_constants.DASHBOARD_HOME_TEMPLATE, context=context,
                  assets=assets)


class DashboardRegistryRecords(DashboardRecords):
    """ List the records for the registry
    """

    def _get_list_name_in_shema_from_slug(self, role_name_list, custom_resources):
        """ Get list of name in schema for each role in request

        Args:
            role_name_list:
            custom_resources:
        Returns:
        """
        list_name_in_schema = []
        for role in role_name_list:
            for cr in custom_resources:
                if cr.slug == role:
                    list_name_in_schema.append(cr.name_in_schema)

        return list_name_in_schema

    def load_records(self, request, is_published, custom_resources):
        """ Get list of records

             Args:
                 role_name_list:
                 custom_resources:
             Returns:
                 filtered_data
             """
        role_name_list = self._get_list_name_in_shema_from_slug(request.GET.getlist('role', []), custom_resources)
        filtered_data = []
        try:
            loaded_data = data_api.execute_query(
                create_query_dashboard_resources(
                    request, role_name_list, self.administration
                ),
                request.user)
        except AccessControlError:
            loaded_data = []
        for data in loaded_data:
            if (is_published is None or
                    (is_published == 'true' and data_api.is_data_public(data)) or
                    (is_published == 'false' and not data_api.is_data_public(data))):
                filtered_data.append(data)
        return filtered_data

    def load_drafts(self, request, context):
        """ Get list of drafts

             Args:
                 request:
                 context:
             Returns:
                 filtered_data
             """

        role_name_list = request.GET.getlist('role', [])
        filtered_data = []

        if self.administration:
            forms = curate_data_structure_api.get_all_with_no_data()
        else:
            forms = curate_data_structure_api.get_all_by_user_id_with_no_data(request.user.id)

        detailed_forms = []
        for form in forms:
            try:
                role = ', '.join([custom_resource_api.get_by_role_for_current_template(x).title
                                  for x in curate_data_structure_registry_api.get_role(form)
                                  ]
                                 if form.form_string
                                 else ['None'])
            except exceptions.ModelError:
                role = 'None'
            if role_name_list != []:
                if '-'.join(role.lower().split()) in context['roles']:
                    detailed_forms.append({'form': form,
                                           'role': role})
            else:
                detailed_forms.append({'form': form,
                                       'role': role})
        filtered_data.extend(detailed_forms)
        return filtered_data

    def get(self, request, *args, **kwargs):
        """ Retrieve a list of drafts or records

        Args:

            request: HTTP request

        Returns:

            - code: 200
              content: Data
            - code: 404
              content: Object was not found
            - code: 500
              content: Internal server error
        """


        # TODO: use custom_resource to get cr_type_all
        cr_type_all = custom_resource_api.get_current_custom_resource_type_all()

        custom_resources = list(custom_resource_api.get_all_of_current_template().order_by('sort'))
        # Get arguments

        is_published = request.GET.get('ispublished', None)
        is_published = None if is_published not in ['true', 'false', 'draft'] else is_published
        page = request.GET.get('page', 1)
        if is_published == 'draft':
            document = dashboard_common_constants.FUNCTIONAL_OBJECT_ENUM.FORM.value
            template = dashboard_constants.DASHBOARD_FORMS_TEMPLATE_TABLE_PAGINATION
        else:
            document = dashboard_common_constants.FUNCTIONAL_OBJECT_ENUM.RECORD.value
            template = self.data_template

        context = {'page': page,
                   'roles': ','.join(request.GET.getlist('role', [cr_type_all.slug])),
                   'ispublished': is_published}

        # Get resources
        if is_published == 'draft':
            filtered_data = self.load_drafts(request, context)
        else:
            filtered_data = self.load_records(request, is_published, custom_resources)

        # Paginator
        results_paginator = ResultsPaginator.get_results(
            filtered_data, page, settings.RECORD_PER_PAGE_PAGINATION
        )

        # Data context
        if is_published != "draft":
            results_paginator.object_list = self._format_data_context_registry(
                results_paginator.object_list, is_published
            )

        # Add user_form for change owner
        user_form = UserForm(request.user)
        context.update({
            'number_total': len(filtered_data),
            'user_data': results_paginator,
            'user_form': user_form,
            'document': document,
            'template': template,
            'action_form': ActionForm([('2', 'Change owner of selected records')]),
            'menu': self.administration,
            'administration': self.administration,
            'username_list': get_id_username_dict(user_api.get_all_users()),
            'resources': True,
            'url_resources': reverse('admin:core_dashboard_records') if self.administration else
            reverse('core_dashboard_records'),
            'custom_resources': custom_resources,
            'display_not_resource': True,  # display all resource
            'role_custom_resource_type_all': cr_type_all.slug,
            'list_role_custom_resource': ','.join([cr.slug for cr in custom_resources
                                                   if custom_resource_api._is_custom_resource_type_resource(cr)
                                                   and cr.display_icon]),
            'type_resource': CUSTOM_RESOURCE_TYPE.RESOURCE.value,
        })

        modals = ["core_main_app/user/workspaces/list/modals/assign_workspace.html",
                  dashboard_common_constants.MODALS_COMMON_DELETE,
                  dashboard_common_constants.MODALS_COMMON_CHANGE_OWNER,
                  EditDataView.get_modal_html_path()
                  ]

        assets = self._get_assets()

        return self.common_render(request, self.template,
                                  context=context,
                                  assets=assets,
                                  modals=modals)

    # FIXME is_published is never used
    def _format_data_context_registry(self, data_list, is_published):
        data_context_list = []
        username_list = dict((str(x.id), x.username) for x in user_api.get_all_users())
        for data in data_list:
            data_context_list.append({
                'data': data,
                'username_list': username_list,
                'data_status': get_status(data),
                'data_status_values': DataStatus,
                'data_role': ', '.join([_get_role_label(x) for x in get_role(data)]),
                'can_read': True,
                'can_write': True,
                'is_owner': True,
                'can_change_workspace': check_if_workspace_can_be_changed(data),
                'can_set_public': not data_api.is_data_public(data)
            })
        return data_context_list

    def _get_assets(self):
        # add js & css for the super class
        assets = super(DashboardRegistryRecords, self)._get_assets()
        # add css relatives to the registry
        assets['css'].append("core_dashboard_registry_app/user/css/list/records.css")
        assets['css'].append("core_main_registry_app/user/css/resource_banner/resource_banner.css")
        assets['css'].append(dashboard_constants.CSS_SELECTION)
        # add js relatives to the registry
        assets['js'].append({
            "path": 'core_dashboard_registry_app/user/js/list/records.js',
            "is_raw": False
        })
        assets['js'].append({
            "path": 'core_dashboard_registry_app/user/js/list/records.raw.js',
            "is_raw": True
        })
        assets['js'].append({
            "path": dashboard_constants.JS_PUBLISH_RESOURCE,
            "is_raw": False
        })
        assets['js'].append({
            "path": dashboard_constants.JS_RECORD_REGISTRY,
            "is_raw": False
        })
        assets['js'].append({
            "path": 'core_dashboard_registry_app/user/js/get_url.js',
            "is_raw": False
        })
        assets['js'].append(
            EditDataView.get_modal_js_path()
        )
        return assets


class DashboardRegistryWorkspaceRecords(DashboardWorkspaceRecords):
    """ List the records of a workspace for the registry.
    """

    def _format_data_context(self, data_list, user, user_can_read, user_can_write):
        detailed_user_data = []
        username_list = get_id_username_dict(user_api.get_all_users())
        for data in data_list:
            is_owner = str(data.user_id) == str(user.id) or self.administration
            detailed_user_data.append({
                'data': data,
                'username_list': username_list,
                'data_status': get_status(data),
                'data_status_values': DataStatus,
                'data_role': ', '.join([_get_role_label(x) for x in get_role(data)]),
                'can_read': user_can_read or is_owner,
                'can_write': user_can_write or is_owner,
                'is_owner': is_owner
            })
        return detailed_user_data

    def _get_modals(self):
        modals = super(DashboardRegistryWorkspaceRecords, self)._get_modals()
        modals.append(EditDataView.get_modal_html_path())
        return modals

    def _get_assets(self):
        # add js & css for the super class
        assets = super(DashboardRegistryWorkspaceRecords, self)._get_assets()
        # add css relatives to the registry
        assets['css'].append("core_dashboard_registry_app/user/css/list/records.css")
        # add js relatives to the registry
        assets['js'].append({
            "path": 'core_dashboard_registry_app/user/js/list/records.js',
            "is_raw": False
        })
        assets['js'].append({
            "path": 'core_dashboard_registry_app/user/js/list/records.raw.js',
            "is_raw": True
        })
        assets['js'].append({
            "path": 'core_dashboard_registry_app/user/js/get_url.js',
            "is_raw": False
        })
        assets['js'].append(
            EditDataView.get_modal_js_path()
        )
        return assets


class DashboardRegistryForms(DashboardForms):
    """ List the forms.
    """

    def _get_detailed_forms(self, forms):
        detailed_forms = []
        for form in forms:
            try:
                role = ', '.join([custom_resource_api.get_by_role_for_current_template(x).title
                                  for x in curate_data_structure_registry_api.get_role(form)
                                  ]
                                 if form.form_string
                                 else ['None'])
            except exceptions.ModelError:
                role = 'None'

            detailed_forms.append({'form': form,
                                   'role': role})
        return detailed_forms


def _get_role_label(role):
    """ Get role label

    Get role label from custom resources if found, get it from xsd otherwise

    Args:
        role:

    Returns:

    """
    try:
        return custom_resource_api.get_by_role_for_current_template(role).title
    except (exceptions.ModelError, exceptions.DoesNotExist):
        return role
