from collections import OrderedDict

from django.db.models import Prefetch, Q
from django.shortcuts import get_object_or_404, redirect, render

from .models import (
    ArchiveCategory,
    PortfolioItem,
    PortfolioMedia,
    PortfolioMediaAnnotation,
)


def _category_items(category):
    return (
        PortfolioItem.objects.filter(category=category)
        .select_related("category")
        .prefetch_related(
            Prefetch(
                "media_items",
                queryset=PortfolioMedia.objects.order_by("-is_primary", "id"),
            )
        )
    )


def _apply_item_search(items, query):
    if not query:
        return items

    return items.filter(
        Q(title__icontains=query)
        | Q(inventory_id__icontains=query)
        | Q(description__icontains=query)
        | Q(place_created__icontains=query)
        | Q(date_text__icontains=query)
        | Q(materials_and_techniques__icontains=query)
        | Q(model_viewer_url__icontains=query)
    )


def home(request):
    categories = ArchiveCategory.objects.all().order_by("name")
    return render(request, "home.html", {"categories": categories})


def category_timeline(request, slug):
    category = get_object_or_404(ArchiveCategory, slug=slug)

    if category.is_3d_models:
        q = (request.GET.get("q") or "").strip()
        sort = (request.GET.get("sort") or "title_asc").strip()

        items = _apply_item_search(_category_items(category), q)
        if sort == "title_desc":
            items = items.order_by("-title")
        else:
            sort = "title_asc"
            items = items.order_by("title")

        return render(
            request,
            "sections/category_direct_items.html",
            {
                "category": category,
                "items": items,
                "q": q,
                "sort": sort,
            },
        )

    items = PortfolioItem.objects.filter(category=category)
    decade_map = OrderedDict()

    years = (
        items.exclude(year__isnull=True).values_list("year", flat=True).order_by("year")
    )

    seen_decades = set()
    for year in years:
        decade = (year // 10) * 10
        if decade not in seen_decades:
            seen_decades.add(decade)
            decade_map[decade] = {
                "label": f"{decade}s",
                "count": items.filter(year__gte=decade, year__lt=decade + 10).count(),
                "url_value": decade,
            }

    undated_count = items.filter(year__isnull=True).count()
    if undated_count:
        decade_map["undated"] = {
            "label": "Undated",
            "count": undated_count,
            "url_value": "undated",
        }

    return render(
        request,
        "sections/category_timeline.html",
        {
            "category": category,
            "decade_map": decade_map,
        },
    )


def items_by_category_decade(request, slug, decade):
    category = get_object_or_404(ArchiveCategory, slug=slug)

    if category.is_3d_models:
        return redirect("category_timeline", slug=category.slug)

    q = (request.GET.get("q") or "").strip()
    sort = (request.GET.get("sort") or "year_asc").strip()
    items = _category_items(category)

    if decade == "undated":
        items = items.filter(year__isnull=True)
        decade_label = "Undated"
    else:
        decade_int = int(decade)
        items = items.filter(year__gte=decade_int, year__lt=decade_int + 10)
        decade_label = f"{decade_int}s"

    items = _apply_item_search(items, q)

    if sort == "year_desc":
        items = items.order_by("-year", "title")
    elif sort == "title_asc":
        items = items.order_by("title")
    elif sort == "title_desc":
        items = items.order_by("-title")
    else:
        sort = "year_asc"
        items = items.order_by("year", "title")

    return render(
        request,
        "sections/items_by_category_decade.html",
        {
            "category": category,
            "items": items,
            "decade": decade,
            "decade_label": decade_label,
            "q": q,
            "sort": sort,
        },
    )


def portfolio_item_detail(request, pk):
    item = get_object_or_404(
        PortfolioItem.objects.select_related("category").prefetch_related(
            Prefetch(
                "media_items",
                queryset=PortfolioMedia.objects.prefetch_related(
                    Prefetch(
                        "annotations",
                        queryset=PortfolioMediaAnnotation.objects.filter(
                            is_active=True
                        ).order_by("sort_order", "id"),
                    )
                ).order_by("-is_primary", "id"),
            )
        ),
        pk=pk,
    )

    media_items = list(item.media_items.all())
    primary_media = next(
        (media for media in media_items if media.is_primary),
        media_items[0] if media_items else None,
    )

    return render(
        request,
        "sections/portfolio_item_detail.html",
        {
            "item": item,
            "media_items": media_items,
            "primary_media": primary_media,
        },
    )
