# core/views_user_features.py
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse, HttpResponseBadRequest
from django.views.decorators.http import require_POST, require_GET
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from django.forms.models import model_to_dict

from .models import Entry  # existing
from .models_user import UserPrefs, SearchHistory, ViewedIllustration
from django.views.decorators.cache import never_cache


# ---------- Font size prefs ----------
@login_required
@require_POST
def api_set_font_size(request):
    size = (request.POST.get("size") or "").lower()
    if size not in ("small", "default", "large", "xlarge"):
        return JsonResponse({"ok": False, "error": "bad_size"}, status=400)
    prefs, _ = UserPrefs.objects.get_or_create(user=request.user)
    prefs.font_size = size
    prefs.save(update_fields=["font_size"])
    return JsonResponse({"ok": True})


@login_required
@require_GET
def api_get_prefs(request):
    prefs, _ = UserPrefs.objects.get_or_create(user=request.user)
    return JsonResponse({"ok": True, "font_size": prefs.font_size})


# ---------- Search history ----------
# We use Beacon here, so CSRF headers aren’t available -> mark this one csrf_exempt
@login_required
@csrf_exempt         # keep this since you use sendBeacon
@require_POST
def api_log_search(request):
    q = (request.POST.get("q") or "").strip()

    # Collect selected fields from form-style keys: sel[subject]=on
    selected = {}
    for k in request.POST:
        if k.startswith("sel[") and k.endswith("]"):
            name = k[4:-1]
            selected[name] = request.POST.get(k) in ("1", "true", "on", "yes")

    # De-dupe consecutive identical searches; if identical, bump timestamp
    last = SearchHistory.objects.filter(user=request.user).order_by("-created_at").first()
    if last and last.q == q and last.selected == selected:
        # bump to "most recent"
        last.created_at = timezone.now()
        last.save(update_fields=["created_at"])
    else:
        SearchHistory.objects.create(user=request.user, q=q, selected=selected)

    # Trim to last 10
    ids = list(
        SearchHistory.objects.filter(user=request.user)
        .order_by("-created_at")
        .values_list("id", flat=True)[:10]
    )
    SearchHistory.objects.filter(user=request.user).exclude(id__in=ids).delete()
    return JsonResponse({"ok": True})


@login_required
@require_GET
@never_cache
def api_get_search_history(request):
    items_qs = (
        SearchHistory.objects.filter(user=request.user)
        .order_by("-created_at")
        .values("q", "selected", "created_at")
    )
    data = [
        {"q": i["q"], "selected": i["selected"], "ts": i["created_at"].isoformat()}
        for i in items_qs
    ]
    resp = JsonResponse({"ok": True, "items": data})
    resp["Cache-Control"] = "no-store"
    return resp



# ---------- Recently viewed ----------
@login_required
@require_POST
def api_log_view(request, entry_id):
    try:
        e = Entry.objects.get(pk=entry_id)
    except Entry.DoesNotExist:
        return JsonResponse({"ok": False, "error": "notfound"}, status=404)

    ViewedIllustration.objects.create(user=request.user, entry=e)

    # Keep only the 50 most recent
    ids = list(
        ViewedIllustration.objects.filter(user=request.user)
        .order_by("-viewed_at")
        .values_list("id", flat=True)[:50]
    )
    ViewedIllustration.objects.filter(user=request.user).exclude(id__in=ids).delete()
    return JsonResponse({"ok": True})


@login_required
@require_GET
@never_cache
def api_get_recent_views(request):
    rows = (
        ViewedIllustration.objects.filter(user=request.user)
        .select_related("entry")
        .order_by("-viewed_at")[:10]
    )

    def first_words(text, n=20):
        import re as _re
        clean = _re.sub(r"\s+", " ", (text or "")).strip()
        if not clean:
            return ""
        words = clean.split(" ")
        return clean if len(words) <= n else " ".join(words[:n]) + "…"

    data = [
        {
            "entry_id": r.entry_id,
            "viewed_at": r.viewed_at.isoformat(),
            "illustration": r.entry.illustration or "",   # <-- what the UI expects
            "snippet": first_words(r.entry.illustration or "", 20),
        }
        for r in rows
    ]
    resp = JsonResponse({"ok": True, "items": data})
    resp["Cache-Control"] = "no-store"
    return resp