from urllib.parse import urlencode

from django.contrib import admin
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model
from django.http import HttpRequest
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.urls import path
from django.urls import reverse
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _


class BaseProcessActionsAdminMixin:
    def get_action_methods(self):
        return {}

    def _get_path_info(self):
        return self.model._meta.app_label, self.model._meta.model_name  # noqa

    def get_redirect_url__to_referer(self, request: HttpRequest):
        preserved_filters = self.get_preserved_filters(request)  # noqa
        opts = self.model._meta  # noqa

        redirect_url = add_preserved_filters(
            {'preserved_filters': preserved_filters, 'opts': opts},
            request.META.get('HTTP_REFERER', '/'),
        )

        return redirect_url

    def process_action(
        self, request, obj_id, action_key, **kwargs,
    ):
        action_methods = self.get_action_methods()
        action = action_methods[action_key]
        obj = self.get_object(request, obj_id)  # noqa
        return action(request, obj)


class CRUDHistoryAdminMixin(BaseProcessActionsAdminMixin, admin.ModelAdmin):
    CRUD_HISTORY = "crud_history"
    crud_history_translated_title = _('CRUD history')

    def get_urls(self) -> list:
        urls = super().get_urls()
        info = self._get_path_info()
        crud_history_urls = [
            path(
                f'<path:object_id>/{self.CRUD_HISTORY}/',
                self.admin_site.admin_view(self.crud_history_view),
                name=f'%s_%s_{self.CRUD_HISTORY}' % info,
            ),
        ]
        return crud_history_urls + urls

    def get_action_methods(self) -> dict:
        methods = super().get_action_methods()
        methods.update(
            {self.CRUD_HISTORY: self.crud_history_action, }
        )
        return methods

    def crud_history_view(self, request: HttpRequest, object_id: int):
        return self.process_action(request, object_id, self.CRUD_HISTORY)

    def crud_history_action(self, request: HttpRequest, obj: Model) -> HttpResponseRedirect:
        base_history_url = reverse(f"admin:easyaudit_crudevent_changelist", )
        app_label, model_name = self._get_path_info()
        content_type = ContentType.objects.get_by_natural_key(app_label, model_name)

        params = {
            # "content_type__app_label": app_label,
            "content_type__id": content_type.id,
            # "content_type__model_name": model_name,
            "object_id": obj.id,
        }

        params = urlencode(params)
        history_url = f"{base_history_url}?{params}"

        return redirect(history_url)

    crud_history_action.short_description = crud_history_translated_title

    def get_crud_history_url(self, obj: Model) -> str:
        info = self._get_path_info()
        return reverse(f"admin:%s_%s_{self.CRUD_HISTORY}" % info, args=[obj.pk])

    def crud_history_link(self, obj: Model) -> str:
        crud_history_url = self.get_crud_history_url(obj=obj)
        crud_history_a = f"<a href={crud_history_url}>> {self.crud_history_translated_title}</a>"

        return format_html(crud_history_a)

    crud_history_link.allow_tags = True
    crud_history_link.short_description = crud_history_translated_title


# Example
class SomeModelAdmin(CRUDHistoryAdminMixin):
    list_display = "id", "crud_history_link",
