import random

from django.db.models import Prefetch
from django.http import Http404
from django.http import JsonResponse
from django.shortcuts import render
from django.urls import reverse
from django.views import View
from django.views.generic import DetailView, ListView, TemplateView

from apps.products.models import MainProduct, SubProduct
from apps.projects.models import ProjectBrief

from .forms import ContactForm
from .models import (
    AboutSection,
    ContactSubmission,
    ContactSubmissionAttachment,
    CustomPage,
    FAQEntry,
    HeroSection,
    HomepageSection,
    PageVideo,
)

VIDEO_PREVIEW_LIMIT = 3
VIDEO_ARCHIVE_PAGE_SIZE = 6


def _video_preview_context(queryset, archive_url):
    total = queryset.count()
    return {
        "videos": queryset[:VIDEO_PREVIEW_LIMIT],
        "videos_total_count": total,
        "videos_archive_url": archive_url if total > VIDEO_PREVIEW_LIMIT else "",
    }


def _homepage_products_catalog_queryset():
    return (
        MainProduct.objects.filter(is_active=True)
        .prefetch_related(
            Prefetch(
                "sub_products",
                queryset=SubProduct.objects.filter(is_active=True).order_by("order", "name"),
            )
        )
        .order_by("order", "name")
    )


class HomeView(TemplateView):
    template_name = "pages/home.html"

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["hero"] = HeroSection.objects.first()
        ctx["homepage_sections"] = (
            HomepageSection.objects.filter(is_active=True)
            .prefetch_related("items")
            .order_by("order")
        )
        ctx["homepage_products"] = (
            MainProduct.objects.filter(is_active=True, show_on_homepage=True)
            .order_by("homepage_order", "order")
        )
        ctx["homepage_products_catalog"] = _homepage_products_catalog_queryset()
        ctx["website_project_briefs"] = (
            ProjectBrief.objects.filter(show_on_website=True)
            .order_by("-submitted_at")
        )
        return ctx


class AboutView(TemplateView):
    template_name = "pages/about.html"

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["about_sections"] = (
            AboutSection.objects.filter(is_active=True)
            .prefetch_related("items")
            .order_by("order")
        )
        return ctx


class FAQView(ListView):
    model = FAQEntry
    template_name = "pages/faq.html"
    context_object_name = "faq_entries"
    queryset = FAQEntry.objects.filter(is_active=True)

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        videos = PageVideo.objects.filter(
            page=PageVideo.PAGE_FAQ,
            is_active=True,
        ).order_by("order")
        preview = _video_preview_context(videos, reverse("pages:video_archive", kwargs={"library": PageVideo.PAGE_FAQ}))
        ctx["faq_videos"] = preview["videos"]
        ctx["videos_total_count"] = preview["videos_total_count"]
        ctx["videos_archive_url"] = preview["videos_archive_url"]
        return ctx


class ContactView(View):
    template_name = "pages/contact.html"

    def _new_captcha(self, request):
        a, b = random.randint(1, 9), random.randint(1, 9)
        request.session["captcha_answer"] = a + b
        return f"{a} + {b}"

    def get(self, request, *args, **kwargs):
        videos = PageVideo.objects.filter(
            page=PageVideo.PAGE_CONTACT,
            is_active=True,
        ).order_by("order")
        preview = _video_preview_context(
            videos,
            reverse("pages:video_archive", kwargs={"library": PageVideo.PAGE_CONTACT}),
        )
        return render(
            request,
            self.template_name,
            {
                "form": ContactForm(),
                "captcha_question": self._new_captcha(request),
                "contact_videos": preview["videos"],
                "videos_total_count": preview["videos_total_count"],
                "videos_archive_url": preview["videos_archive_url"],
            },
        )

    def post(self, request, *args, **kwargs):
        form = ContactForm(
            request.POST,
            file_list=request.FILES.getlist("attachments"),
        )
        expected = request.session.get("captcha_answer")
        captcha_question = self._new_captcha(request)

        captcha_ok = False
        try:
            captcha_ok = int(request.POST.get("captcha_answer", "")) == expected
        except (ValueError, TypeError):
            pass

        if form.is_valid() and captcha_ok:
            submission = form.save()
            for uploaded_file, original_name in form.cleaned_data.get(
                "attachments", []
            ):
                attachment = ContactSubmissionAttachment(
                    submission=submission,
                    original_filename=original_name,
                )
                attachment.file.save(original_name, uploaded_file, save=True)
            return JsonResponse({"success": True})

        errors: dict = {}
        if not captcha_ok:
            errors["captcha"] = ["Incorrect answer — please try again."]
        errors.update(
            {field: [str(e) for e in errs] for field, errs in form.errors.items()}
        )
        return JsonResponse(
            {"success": False, "errors": errors, "captcha_question": captcha_question},
            status=400,
        )


class CustomPageView(DetailView):
    model = CustomPage
    template_name = "pages/custom_page.html"
    context_object_name = "custom_page"
    slug_url_kwarg = "slug"

    def get_queryset(self):
        return CustomPage.objects.filter(is_published=True)

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["page_sections"] = (
            self.object.sections.filter(is_active=True)
            .prefetch_related("items")
            .order_by("order")
        )
        ctx["homepage_products"] = (
            MainProduct.objects.filter(is_active=True, show_on_homepage=True)
            .order_by("homepage_order", "order")
        )
        ctx["homepage_products_catalog"] = _homepage_products_catalog_queryset()
        return ctx


class PageVideoArchiveView(ListView):
    model = PageVideo
    template_name = "videos/archive.html"
    context_object_name = "videos"
    paginate_by = VIDEO_ARCHIVE_PAGE_SIZE

    PAGE_CONFIG = {
        PageVideo.PAGE_CONTACT: ("Contact videos", "Guides and updates from the Tecvico team.", "pages:contact"),
        PageVideo.PAGE_FAQ: ("FAQ videos", "Video answers to common questions.", "pages:faq"),
    }

    def get_page_config(self):
        try:
            return self.PAGE_CONFIG[self.kwargs["library"]]
        except KeyError as exc:
            raise Http404("Video library not found.") from exc

    def get_queryset(self):
        self.get_page_config()
        return PageVideo.objects.filter(
            page=self.kwargs["library"],
            is_active=True,
        ).order_by("order", "pk")

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        title, description, source_url_name = self.get_page_config()
        context.update(
            {
                "library_title": title,
                "library_description": description,
                "library_back_url": reverse(source_url_name),
                "library_back_label": "Back to page",
                "pagination_range": context["paginator"].get_elided_page_range(context["page_obj"].number),
            }
        )
        return context
