import json
from functools import partial
from uuid import UUID

from celery.result import AsyncResult
from django.core.exceptions import PermissionDenied
from django.http import (
    Http404,
    HttpResponseBadRequest,
    HttpResponseRedirect,
    JsonResponse,
)
from django.shortcuts import render
from django.urls import reverse
from django.utils.http import is_safe_url

from judge.tasks import failure, progress, success
from judge.utils.celery import redirect_to_task_status
from judge.utils.views import short_circuit_middleware


def get_task_status(task_id):
    result = AsyncResult(task_id)
    info = result.result
    if result.state == "PROGRESS":
        return {
            "code": "PROGRESS",
            "done": info["done"],
            "total": info["total"],
            "stage": info["stage"],
        }
    elif result.state == "SUCCESS":
        return {"code": "SUCCESS"}
    elif result.state == "FAILURE":
        return {"code": "FAILURE", "error": str(info)}
    else:
        return {"code": "WORKING"}


def task_status(request, task_id):
    try:
        UUID(task_id)
    except ValueError:
        raise Http404()

    redirect = request.GET.get("redirect")
    if not is_safe_url(redirect, allowed_hosts={request.get_host()}):
        redirect = None

    status = get_task_status(task_id)
    if status["code"] == "SUCCESS" and redirect:
        return HttpResponseRedirect(redirect)

    return render(
        request,
        "task_status.html",
        {
            "task_id": task_id,
            "task_status": json.dumps(status),
            "message": request.GET.get("message", ""),
            "redirect": redirect or "",
        },
    )


@short_circuit_middleware
def task_status_ajax(request):
    if "id" not in request.GET:
        return HttpResponseBadRequest(
            'Need to pass GET parameter "id"', content_type="text/plain"
        )
    return JsonResponse(get_task_status(request.GET["id"]))


def demo_task(request, task, message):
    if not request.user.is_superuser:
        raise PermissionDenied()
    result = task.delay()
    return redirect_to_task_status(result, message=message, redirect=reverse("home"))


demo_success = partial(
    demo_task, task=success, message="Running example task that succeeds..."
)
demo_failure = partial(
    demo_task, task=failure, message="Running example task that fails..."
)
demo_progress = partial(
    demo_task, task=progress, message="Running example task that waits 10 seconds..."
)