"""
django-helpdesk - A Django powered ticket tracker for small enterprise.

(c) Copyright 2008 Jutda. All Rights Reserved. See LICENSE for details.

views/public.py - All public facing views, eg non-staff (no authentication
                  required) views.
"""


from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.utils.translation import gettext as _
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
from helpdesk import settings as helpdesk_settings
from helpdesk.decorators import is_helpdesk_staff, protect_view
from helpdesk.lib import text_is_spam
from helpdesk.models import Queue, Ticket, UserSettings
from helpdesk.user import huser_from_request
import helpdesk.views.abstract_views as abstract_views
import helpdesk.views.staff as staff
from importlib import import_module
import logging
from urllib.parse import quote


logger = logging.getLogger(__name__)


def create_ticket(request, *args, **kwargs):
    if is_helpdesk_staff(request.user):
        return staff.CreateTicketView.as_view()(request, *args, **kwargs)
    else:
        return protect_view(CreateTicketView.as_view())(request, *args, **kwargs)


class BaseCreateTicketView(abstract_views.AbstractCreateTicketMixin, FormView):

    def get_form_class(self):
        try:
            the_module, the_form_class = helpdesk_settings.HELPDESK_PUBLIC_TICKET_FORM_CLASS.rsplit(
                ".", 1)
            the_module = import_module(the_module)
            the_form_class = getattr(the_module, the_form_class)
        except Exception as e:
            raise ImproperlyConfigured(
                f"Invalid custom form class {helpdesk_settings.HELPDESK_PUBLIC_TICKET_FORM_CLASS}"
            ) from e
        return the_form_class

    def dispatch(self, *args, **kwargs):
        request = self.request
        if not request.user.is_authenticated and helpdesk_settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT:
            return HttpResponseRedirect(reverse('login'))

        if is_helpdesk_staff(request.user) or \
                (request.user.is_authenticated and
                 helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE):
            try:
                if request.user.usersettings_helpdesk.login_view_ticketlist:
                    return HttpResponseRedirect(reverse('helpdesk:list'))
                else:
                    return HttpResponseRedirect(reverse('helpdesk:dashboard'))
            except UserSettings.DoesNotExist:
                return HttpResponseRedirect(reverse('helpdesk:dashboard'))
        return super().dispatch(*args, **kwargs)

    def get_initial(self):
        initial_data = super().get_initial()

        # add pre-defined data for public ticket
        if hasattr(settings, 'HELPDESK_PUBLIC_TICKET_QUEUE'):
            # get the requested queue; return an error if queue not found
            try:
                initial_data['queue'] = Queue.objects.get(
                    slug=settings.HELPDESK_PUBLIC_TICKET_QUEUE,
                    allow_public_submission=True
                ).id
            except Queue.DoesNotExist as e:
                logger.fatal(
                    "Public queue '%s' is configured as default but can't be found",
                    settings.HELPDESK_PUBLIC_TICKET_QUEUE
                )
                raise ImproperlyConfigured(
                    "Wrong public queue configuration") from e
        if hasattr(settings, 'HELPDESK_PUBLIC_TICKET_PRIORITY'):
            initial_data['priority'] = settings.HELPDESK_PUBLIC_TICKET_PRIORITY
        if hasattr(settings, 'HELPDESK_PUBLIC_TICKET_DUE_DATE'):
            initial_data['due_date'] = settings.HELPDESK_PUBLIC_TICKET_DUE_DATE
        return initial_data

    def get_form_kwargs(self, *args, **kwargs):
        kwargs = super().get_form_kwargs(*args, **kwargs)
        if '_hide_fields_' in self.request.GET:
            kwargs['hidden_fields'] = self.request.GET.get(
                '_hide_fields_', '').split(',')
        kwargs['readonly_fields'] = self.request.GET.get(
            '_readonly_fields_', '').split(',')
        return kwargs

    def form_valid(self, form):
        request = self.request
        if text_is_spam(form.cleaned_data['body'], request):
            # This submission is spam. Let's not save it.
            return render(request, template_name='helpdesk/public_spam.html')
        else:
            ticket = form.save(
                user=self.request.user if self.request.user.is_authenticated else None)
            try:
                return HttpResponseRedirect('%s?ticket=%s&email=%s&key=%s' % (
                    reverse('helpdesk:public_view'),
                    ticket.ticket_for_url,
                    quote(ticket.submitter_email),
                    ticket.secret_key)
                )
            except ValueError:
                # if someone enters a non-int string for the ticket
                return HttpResponseRedirect(reverse('helpdesk:home'))


class CreateTicketIframeView(BaseCreateTicketView):
    template_name = 'helpdesk/public_create_ticket_iframe.html'

    @csrf_exempt
    @xframe_options_exempt
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

    def form_valid(self, form):
        if super().form_valid(form).status_code == 302:
            return HttpResponseRedirect(reverse('helpdesk:success_iframe'))


class SuccessIframeView(TemplateView):
    template_name = 'helpdesk/success_iframe.html'

    @xframe_options_exempt
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)


class CreateTicketView(BaseCreateTicketView):
    template_name = 'helpdesk/public_create_ticket.html'

    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        # Add the CSS error class to the form in order to better see them in
        # the page
        form.error_css_class = 'text-danger'
        return form


class Homepage(CreateTicketView):
    template_name = 'helpdesk/public_homepage.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['kb_categories'] = huser_from_request(
            self.request).get_allowed_kb_categories()
        return context


class SearchForTicketView(TemplateView):
    template_name = 'helpdesk/public_view_form.html'

    def get(self, request, *args, **kwargs):
        if hasattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC') and settings.HELPDESK_VIEW_A_TICKET_PUBLIC:
            context = self.get_context_data(**kwargs)
            return self.render_to_response(context)
        else:
            raise PermissionDenied("Public viewing of tickets without a secret key is forbidden.")

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        request = self.request
        email = request.GET.get('email', None)
        error_message = kwargs.get('error_message', None)

        context.update({
            'ticket': False,
            'email': email,
            'error_message': error_message,
            'helpdesk_settings': helpdesk_settings,
        })
        return context


class ViewTicket(TemplateView):
    template_name = 'helpdesk/public_view_ticket.html'


    def get(self, request, *args, **kwargs):
        ticket_req = request.GET.get('ticket', None)
        email = request.GET.get('email', None)
        key = request.GET.get('key', '')

        if not (ticket_req and email):
            if ticket_req is None and email is None:
                return SearchForTicketView.as_view()(request)
            else:
                return SearchForTicketView.as_view()(request, _('Missing ticket ID or e-mail address. Please try again.'))

        try:
            queue, ticket_id = Ticket.queue_and_id_from_query(ticket_req)
            if request.user.is_authenticated and request.user.email == email:
                ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email)
            elif hasattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC') and settings.HELPDESK_VIEW_A_TICKET_PUBLIC:
                ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email)
            else:
                ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email, secret_key__iexact=key)
        except (ObjectDoesNotExist, ValueError):
            return SearchForTicketView.as_view()(request, _('Invalid ticket ID or e-mail address. Please try again.'))

        if 'close' in request.GET and ticket.status == Ticket.RESOLVED_STATUS:
            from helpdesk.update_ticket import update_ticket
            update_ticket(
                request.user,
                ticket,
                public=True,
                comment=_('Submitter accepted resolution and closed ticket'),
                new_status=Ticket.CLOSED_STATUS,
            )
            return HttpResponseRedirect(ticket.ticket_url)

        # Prepare context for rendering
        context = {
            'key': key,
            'mail': email,
            'ticket': ticket,
            'helpdesk_settings': helpdesk_settings,
            'next': self.get_next_url(ticket_id)
        }
        return self.render_to_response(context)

    def get_next_url(self, ticket_id):
        redirect_url = ''
        if is_helpdesk_staff(self.request.user):
            redirect_url = reverse('helpdesk:view', args=[ticket_id])
            if 'close' in self.request.GET:
                redirect_url += '?close'
        elif helpdesk_settings.HELPDESK_NAVIGATION_ENABLED:
            redirect_url = reverse('helpdesk:view', args=[ticket_id])
        return redirect_url


class MyTickets(TemplateView):
    template_name = 'helpdesk/my_tickets.html'

    def get(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseRedirect(reverse('helpdesk:login'))

        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)


def change_language(request):
    return_to = ''
    if 'return_to' in request.GET:
        return_to = request.GET['return_to']

    return render(request, 'helpdesk/public_change_language.html', {'next': return_to})