import importlib
import inspect
import json

from celery import current_app
from django.conf import settings
from django_celery_beat.models import PeriodicTask, CrontabSchedule
from drf_spectacular.utils import extend_schema
from rest_framework import viewsets, filters
from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from utg_base.api.permissions import IsSuperUser
from utg_base.celery.serializers import PeriodicTaskSerializer, PeriodTaskRunSerializer
from utg_base.utils.translation import translate as _


@extend_schema(tags=['admin/periodic-tasks'])
class PeriodicTaskViewSet(viewsets.ModelViewSet):
    http_method_names = ['get', 'patch']
    queryset = PeriodicTask.objects.all()
    serializer_class = PeriodicTaskSerializer
    permission_classes = [IsSuperUser]
    filter_backends = [filters.SearchFilter]
    search_fields = ['name']

    @staticmethod
    def build_task_registry():
        registry = {}

        for cron_task_app in settings.CRON_TASK_APPS:
            tasks_module = importlib.import_module(f"{cron_task_app}.tasks")
            tasks = getattr(tasks_module, "tasks", [])

            for task in tasks:
                task_class = task["task"]

                argspec = inspect.getfullargspec(task_class.run)
                args = [a for a in argspec.args if a != "self"]

                registry[task_class.name] = args

        return registry

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context["task_registry"] = self.build_task_registry()
        return context

    @extend_schema(request={'application/json': PeriodicTaskSerializer()})
    def partial_update(self, request, *args, **kwargs):
        crontab = request.data.pop('crontab')
        response = super().partial_update(request, *args, **kwargs)

        if crontab:
            instance = self.get_object()
            crontab, _ = CrontabSchedule.objects.get_or_create(**crontab)

            instance.crontab = crontab
            instance.save()

        return Response(self.serializer_class(instance).data)


@extend_schema(tags=['admin/periodic-tasks'])
class PeriodicTaskRunNowView(APIView):
    serializer_class = PeriodTaskRunSerializer
    permission_classes = [IsAuthenticated]

    @extend_schema(request=PeriodTaskRunSerializer)
    def patch(self, request, pk):
        try:
            periodic_task = PeriodicTask.objects.get(pk=pk)
        except PeriodicTask.DoesNotExist:
            raise NotFound(detail=_("Periodic task not found"))

        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        params = serializer.validated_data.get('params', {})

        if not periodic_task.enabled:
            raise ValidationError(detail=_("Task is disabled"))

        args = json.loads(periodic_task.args) if periodic_task.args else []
        kwargs = json.loads(periodic_task.kwargs) if periodic_task.kwargs else {}

        if params:
            kwargs.update(params)

        task = current_app.send_task(
            periodic_task.task,
            args=args,
            kwargs=kwargs,
            countdown=0,
            headers={'periodic_task_name': periodic_task.name}
        )

        return Response({
            "detail": _("Task successfully triggered"),
            "task_id": task.id,
            "task_name": periodic_task.name,
            "celery_task": periodic_task.task,
        })
