from __future__ import annotations

from typing import TYPE_CHECKING

from django.contrib.auth.decorators import permission_required
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.urls import reverse

from django_spire.contrib.form.utils import show_form_errors
from django_spire.contrib.generic_views import modal_views, portal_views
from django_spire.core.redirect.safe_redirect import safe_redirect_url
from django_spire.core.shortcuts import get_object_or_null_obj
from django_spire.history.activity.utils import add_form_activity

import django_glue as dg

from ${module_path} import forms, models

if TYPE_CHECKING:
    from django.core.handlers.wsgi import WSGIRequest
    from django.http import HttpResponseRedirect


@permission_required('${permission_prefix}.delete_${model_instance_name}')
def ${delete_modal_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
    ${context_single_var} = get_object_or_404(models.${model_class_name}, pk=pk)

    form_action = reverse(
        '${url_reverse_path}:form:delete_modal',
        kwargs={'pk': pk}
    )

    def add_activity() -> None:
        ${context_single_var}.add_activity(
            user=request.user,
            verb='deleted',
            information=f'{request.user.get_full_name()} deleted a ${model_instance_name}.'
        )

    fallback = reverse('${url_reverse_path}:page:list')
    return_url = safe_redirect_url(request, fallback=fallback)

    return modal_views.dispatch_modal_delete_form_content(
        request,
        obj=${context_single_var},
        form_action=form_action,
        activity_func=add_activity,
        return_url=return_url,
    )


@permission_required('${permission_prefix}.delete_${model_instance_name}')
def ${delete_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
    ${context_single_var} = get_object_or_404(models.${model_class_name}, pk=pk)

    return_url = request.GET.get(
        'return_url',
        reverse('${url_reverse_path}:page:list')
    )

    return portal_views.delete_form_view(
        request,
        obj=${context_single_var},
        return_url=return_url
    )


@permission_required('${permission_prefix}.add_${model_instance_name}')
def ${create_modal_view_name}(request: WSGIRequest) -> TemplateResponse:
    return _modal_view(request)


@permission_required('${permission_prefix}.change_${model_instance_name}')
def ${update_modal_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
    return _modal_view(request, pk)


def _modal_view(request: WSGIRequest, pk: int = 0) -> TemplateResponse:
    ${context_single_var} = get_object_or_404(models.${model_class_name}, pk=pk)

    dg.glue_model_object(request, '${glue_model_key}', ${context_single_var})

    context_data = {
        '${context_single_var}': ${context_single_var}
    }

    return TemplateResponse(
        request,
        context=context_data,
        template='${template_directory_path}/modal/content/${form_template_name}.html'
    )


@permission_required('${permission_prefix}.add_${model_instance_name}')
def ${create_view_name}(request: WSGIRequest) -> TemplateResponse:
    return _form_view(request)


@permission_required('${permission_prefix}.change_${model_instance_name}')
def ${update_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
    return _form_view(request, pk)


def _form_view(request: WSGIRequest, pk: int = 0) -> TemplateResponse|HttpResponseRedirect:
    ${context_single_var} = get_object_or_null_obj(models.${model_class_name}, pk=pk)

    dg.glue_model_object(request, '${glue_model_key}', ${context_single_var}, 'view')

    if request.method == 'POST':
        form = forms.${form_class_name}(request.POST, instance=${context_single_var})

        if form.is_valid():
            ${context_single_var}, _ = ${context_single_var}.services.save_model_obj(**form.cleaned_data)
            add_form_activity(${context_single_var}, pk, request.user)

            return redirect(
                request.GET.get(
                    'return_url',
                    reverse('${url_reverse_path}:page:list')
                )
            )

        show_form_errors(request, form)
    else:
        form = forms.${form_class_name}(instance=${context_single_var})

    return portal_views.form_view(
        request,
        form=form,
        obj=${context_single_var},
        template='${template_directory_path}/page/${form_page_template_name}.html'
    )
