from datetime import date

from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db.models import F, Q, OuterRef, Subquery
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _

from ..celery import app as celery_app, update_orphan_pure_import_events
from ..celery import import_events_from_json, import_events_from_urls
from ..forms import BatchImportationForm
from ..models import Event, BatchImportation, RecurrentImport
from ..import_tasks.extractor import Extractor
from bs4 import BeautifulSoup
import json


@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.view_batchimportation")
def imports(request):
    rel_event = Event.objects.filter(
        import_sources__contains=[OuterRef("url_source")]
    ).values("pk")[:1]
    paginator = Paginator(
        BatchImportation.objects.all()
        .order_by("-created_date")
        .annotate(event_id=Subquery(rel_event)),
        30,
    )
    page = request.GET.get("page")

    today = date.today()

    srcs = RecurrentImport.objects.all().values_list("source")
    in_future = Event.objects.filter(Q(start_day__gte=today))
    nb_in_orphan_import = in_future.filter(
        (
            Q(import_sources__isnull=False)
            & (Q(modified_date__isnull=True) | Q(modified_date__lte=F("imported_date")))
        )
        & ~Q(import_sources__overlap=srcs)
    ).count()

    try:
        response = paginator.page(page)
    except PageNotAnInteger:
        response = paginator.page(1)
    except EmptyPage:
        response = paginator.page(paginator.num_pages)

    return render(
        request,
        "agenda_culturel/imports.html",
        {
            "paginator_filter": response,
            "nb_in_orphan_import": nb_in_orphan_import,
        },
    )


@login_required(login_url="/accounts/login/")
@permission_required(
    [
        "agenda_culturel.add_batchimportation",
        "agenda_culturel.run_batchimportation",
    ]
)
def add_import(request):
    form = BatchImportationForm()

    if request.method == "POST":
        form = BatchImportationForm(request.POST)

        if form.is_valid():
            try:
                # try to load data as a json file
                json.loads(form.data["data"])
                # if data is a json, load it
                import_events_from_json.delay(form.data["data"])
                messages.success(
                    request, _("The import from json has been run successfully.")
                )
            except ValueError:
                # otherwise, consider it as html, extract all urls, and import them
                soup = BeautifulSoup(form.data["data"], "html.parser")
                urls = list(
                    set(
                        [
                            a["href"]
                            for a in soup.find_all("a", href=True)
                            if Extractor.is_known_url_default_extractors(a["href"])
                        ]
                    )
                )
                # then import events from url
                import_events_from_urls.delay(
                    [(u, form.data["category"], form.data["tags"]) for u in urls],
                    user_id=request.user.pk if request.user else None,
                )
                messages.success(
                    request,
                    _(
                        "The import from html ({} detected links) has been run successfully."
                    ).format(len(urls)),
                )

            return HttpResponseRedirect(reverse_lazy("imports"))

    return render(request, "agenda_culturel/batchimportation_form.html", {"form": form})


@login_required(login_url="/accounts/login/")
@permission_required(
    [
        "agenda_culturel.view_batchimportation",
        "agenda_culturel.run_batchimportation",
    ]
)
def cancel_import(request, pk):
    import_process = get_object_or_404(BatchImportation, pk=pk)

    if request.method == "POST":
        celery_app.control.revoke(import_process.celery_id)

        import_process.status = BatchImportation.STATUS.CANCELED
        import_process.save(update_fields=["status"])

        messages.success(request, _("The import has been canceled."))
        return HttpResponseRedirect(reverse_lazy("imports"))
    else:
        cancel_url = reverse_lazy("imports")
        return render(
            request,
            "agenda_culturel/cancel_import_confirm.html",
            {"object": import_process, "cancel_url": cancel_url},
        )


@login_required(login_url="/accounts/login/")
@permission_required(
    [
        "agenda_culturel.view_batchimportation",
        "agenda_culturel.run_batchimportation",
    ]
)
def update_orphan_events(request):
    if request.method == "POST":
        # run recurrent import
        update_orphan_pure_import_events.delay()

        messages.success(request, _("The orphan event update has been launched."))
        return HttpResponseRedirect(reverse_lazy("imports"))
    else:
        today = date.today()

        srcs = RecurrentImport.objects.all().values_list("source")
        in_future = Event.objects.filter(Q(start_day__gte=today))
        nb_in_orphan_import = in_future.filter(
            (
                Q(import_sources__isnull=False)
                & (
                    Q(modified_date__isnull=True)
                    | Q(modified_date__lte=F("imported_date"))
                )
            )
            & ~Q(import_sources__overlap=srcs)
        ).count()
        return render(
            request,
            "agenda_culturel/run_orphan_imports_confirm.html",
            {"nb_in_orphan_import": nb_in_orphan_import},
        )
