""" celery status """
import json

from django.contrib.auth.decorators import login_required, permission_required
from django.http import HttpResponse
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.http import require_GET
from django import forms
import redis

from celerywyrm import settings
from bookwyrm.tasks import (
    app as celery,
    LOW,
    MEDIUM,
    HIGH,
    STREAMS,
    IMAGES,
    SUGGESTED_USERS,
    EMAIL,
    CONNECTORS,
    LISTS,
    INBOX,
    IMPORTS,
    IMPORT_TRIGGERED,
    BROADCAST,
    MISC,
)

r = redis.from_url(settings.REDIS_BROKER_URL)

# pylint: disable= no-self-use
@method_decorator(login_required, name="dispatch")
@method_decorator(
    permission_required("bookwyrm.edit_instance_settings", raise_exception=True),
    name="dispatch",
)
class CeleryStatus(View):
    """Are your tasks running? Well you'd better go catch them"""

    def get(self, request):
        """See workers and active tasks"""
        errors = []
        try:
            inspect = celery.control.inspect()
            stats = inspect.stats()
            active_tasks = inspect.active()
        # pylint: disable=broad-except
        except Exception as err:
            stats = active_tasks = None
            errors.append(err)

        try:
            queues = {
                LOW: r.llen(LOW),
                MEDIUM: r.llen(MEDIUM),
                HIGH: r.llen(HIGH),
                STREAMS: r.llen(STREAMS),
                IMAGES: r.llen(IMAGES),
                SUGGESTED_USERS: r.llen(SUGGESTED_USERS),
                EMAIL: r.llen(EMAIL),
                CONNECTORS: r.llen(CONNECTORS),
                LISTS: r.llen(LISTS),
                INBOX: r.llen(INBOX),
                IMPORTS: r.llen(IMPORTS),
                IMPORT_TRIGGERED: r.llen(IMPORT_TRIGGERED),
                BROADCAST: r.llen(BROADCAST),
                MISC: r.llen(MISC),
            }
        # pylint: disable=broad-except
        except Exception as err:
            queues = None
            errors.append(err)

        form = ClearCeleryForm()

        data = {
            "stats": stats,
            "active_tasks": active_tasks,
            "queues": queues,
            "form": form,
            "errors": errors,
        }
        return TemplateResponse(request, "settings/celery.html", data)

    def post(self, request):
        """Submit form to clear queues"""
        form = ClearCeleryForm(request.POST)
        if form.is_valid():
            if len(celery.control.ping()) != 0:
                return HttpResponse(
                    "Refusing to delete tasks while Celery worker is active"
                )
            pipeline = r.pipeline()
            for queue in form.cleaned_data["queues"]:
                for task in r.lrange(queue, 0, -1):
                    task_json = json.loads(task)
                    if task_json["headers"]["task"] in form.cleaned_data["tasks"]:
                        pipeline.lrem(queue, 0, task)
            results = pipeline.execute()

        return HttpResponse(f"Deleted {sum(results)} tasks")


class ClearCeleryForm(forms.Form):
    """Form to clear queues"""

    queues = forms.MultipleChoiceField(
        label="Queues",
        choices=[
            (LOW, "Low priority"),
            (MEDIUM, "Medium priority"),
            (HIGH, "High priority"),
            (BROADCAST, "Broadcast"),
            (CONNECTORS, "Connectors"),
            (EMAIL, "Email"),
            (IMAGES, "Images"),
            (IMPORTS, "Imports"),
            (IMPORT_TRIGGERED, "Import triggered"),
            (INBOX, "Inbox"),
            (LISTS, "Lists"),
            (MISC, "Misc"),
            (STREAMS, "Streams"),
            (SUGGESTED_USERS, "Suggested users"),
        ],
        widget=forms.CheckboxSelectMultiple,
    )
    tasks = forms.MultipleChoiceField(
        label="Tasks", choices=[], widget=forms.CheckboxSelectMultiple
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        celery.loader.import_default_modules()
        self.fields["tasks"].choices = sorted(
            [(k, k) for k in celery.tasks.keys() if not k.startswith("celery.")]
        )


@require_GET
# pylint: disable=unused-argument
def celery_ping(request):
    """Just tells you if Celery is on or not"""
    try:
        ping = celery.control.inspect().ping()
        if ping:
            return HttpResponse()
    # pylint: disable=broad-except
    except Exception:
        pass

    return HttpResponse(status=500)
