import mimetypes

from django.http import FileResponse, Http404
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.views import View
from django.views.generic import DetailView, ListView, TemplateView

from .models import Article, ArticleCitation, ArticleSection, MainProduct, ProductVideo, SubProduct, SubProductVersion
from .release_assets import FILE_FIELD_BY_ASSET_KEY, RELEASE_ASSET_KEYS, URL_FIELD_BY_ASSET_KEY
from .release_context import build_archive_context, build_release_context

VIDEO_PREVIEW_LIMIT = 3
VIDEO_ARCHIVE_PAGE_SIZE = 6


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


class ReleaseAssetDownloadView(View):
    def get(self, request, version_id, asset):
        if asset not in RELEASE_ASSET_KEYS:
            raise Http404
        version = get_object_or_404(SubProductVersion, pk=version_id, is_active=True)
        parent = version.sub_product or version.main_product
        if parent is None or not parent.is_active:
            raise Http404
        url_field = URL_FIELD_BY_ASSET_KEY[asset]
        if (getattr(version, url_field) or "").strip():
            raise Http404
        file_field = FILE_FIELD_BY_ASSET_KEY[asset]
        release_file = getattr(version, file_field)
        if not release_file:
            raise Http404
        filename = version.release_download_filename(asset)
        content_type, _ = mimetypes.guess_type(filename)
        return FileResponse(
            release_file.open("rb"),
            as_attachment=True,
            filename=filename,
            content_type=content_type or "application/octet-stream",
        )


class ProductOverviewView(ListView):
    model = MainProduct
    template_name = "products/overview.html"
    context_object_name = "main_products"
    queryset = MainProduct.objects.filter(is_active=True).prefetch_related(
        "sub_products"
    )


class MainProductDetailView(DetailView):
    model = MainProduct
    template_name = "products/main_detail.html"
    context_object_name = "main_product"
    slug_url_kwarg = "main_slug"
    queryset = MainProduct.objects.filter(is_active=True).prefetch_related(
        "sub_products"
    )

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["articles"] = self.object.articles.prefetch_related(
            "sections", "citations"
        ).all()
        videos = self.object.videos.filter(is_active=True).order_by("order", "pk")
        context.update(
            _product_video_preview(
                videos,
                reverse("products:main_product_videos", kwargs={"main_slug": self.object.slug}),
            )
        )
        release_context = build_release_context(
            self.object.distribution,
            self.object.versions.filter(is_active=True),
            self.object,
        )
        release_context["versions_archive_url"] = self.object.get_versions_archive_url()
        context.update(release_context)
        return context


class MainProductOlderVersionsView(TemplateView):
    template_name = "products/versions_archive.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        main_product = get_object_or_404(
            MainProduct,
            slug=self.kwargs["main_slug"],
            is_active=True,
        )
        active_versions = main_product.versions.filter(is_active=True)
        context["main_product"] = main_product
        context["sub_product"] = None
        context["product_detail_url"] = main_product.get_absolute_url()
        context.update(
            build_archive_context(
                main_product.distribution, active_versions, main_product
            )
        )
        return context


class SubProductDetailView(TemplateView):
    template_name = "products/sub_detail.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        main_product = get_object_or_404(
            MainProduct,
            slug=self.kwargs["main_slug"],
            is_active=True,
        )
        sub_product = get_object_or_404(
            SubProduct,
            slug=self.kwargs["sub_slug"],
            main_product=main_product,
            is_active=True,
        )
        context["main_product"] = main_product
        context["sub_product"] = sub_product
        context["articles"] = sub_product.articles.prefetch_related(
            "sections", "citations"
        ).all()
        videos = sub_product.videos.filter(is_active=True).order_by("order", "pk")
        context.update(
            _product_video_preview(
                videos,
                reverse(
                    "products:sub_product_videos",
                    kwargs={"main_slug": main_product.slug, "sub_slug": sub_product.slug},
                ),
            )
        )
        context["siblings"] = (
            SubProduct.objects.filter(main_product=main_product, is_active=True)
            .exclude(pk=sub_product.pk)
            .order_by("order", "name")
        )
        active_versions = sub_product.versions.filter(is_active=True)
        release_context = build_release_context(
            sub_product.distribution, active_versions, sub_product
        )
        release_context["versions_archive_url"] = sub_product.get_versions_archive_url()
        context.update(release_context)
        return context


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

    def get_parent(self):
        main_product = get_object_or_404(
            MainProduct,
            slug=self.kwargs["main_slug"],
            is_active=True,
        )
        sub_slug = self.kwargs.get("sub_slug")
        if sub_slug:
            return get_object_or_404(
                SubProduct,
                slug=sub_slug,
                main_product=main_product,
                is_active=True,
            )
        return main_product

    def get_queryset(self):
        self.parent_object = self.get_parent()
        return self.parent_object.videos.filter(is_active=True).order_by("order", "pk")

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update(
            {
                "library_title": f"{self.parent_object.name} videos",
                "library_description": "Tutorials, demonstrations, and technical guides.",
                "library_back_url": self.parent_object.get_absolute_url(),
                "library_back_label": f"Back to {self.parent_object.name}",
                "pagination_range": context["paginator"].get_elided_page_range(context["page_obj"].number),
            }
        )
        return context


class SubProductOlderVersionsView(TemplateView):
    template_name = "products/versions_archive.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        main_product = get_object_or_404(
            MainProduct,
            slug=self.kwargs["main_slug"],
            is_active=True,
        )
        sub_product = get_object_or_404(
            SubProduct,
            slug=self.kwargs["sub_slug"],
            main_product=main_product,
            is_active=True,
        )
        active_versions = sub_product.versions.filter(is_active=True)
        context["main_product"] = main_product
        context["sub_product"] = sub_product
        context["product_detail_url"] = sub_product.get_absolute_url()
        context.update(
            build_archive_context(
                sub_product.distribution, active_versions, sub_product
            )
        )
        return context
