"""Capture page visits, UTM params, and traffic classification."""

from __future__ import annotations

from django.db import IntegrityError, OperationalError
from django.utils.encoding import force_str

from .models import PageVisit
from .traffic import classify_user_agent

UTM_SESSION_KEY = "utm_attribution"
UTM_PARAMS = (
    "utm_source",
    "utm_medium",
    "utm_campaign",
    "utm_term",
    "utm_content",
)

SKIP_PREFIXES = (
    "/static/",
    "/media/",
    "/admin/",
    "/favicon",
    "/robots.txt",
    "/sitemap.xml",
    "/llms.txt",
    "/__debug__",
)

SKIP_NAMES = frozenset(
    {
        "utm_dashboard",
        "leads_list",
        "lead_detail",
        "lead_toggle_contacted",
        "robots_txt",
        "sitemap_xml",
        "llms_txt",
    }
)


def _truncate(value: str, max_len: int) -> str:
    value = force_str(value or "")
    if len(value) <= max_len:
        return value
    return value[: max_len - 1] + "…"


def extract_utm_from_get(get) -> dict[str, str]:
    found = {}
    for key in UTM_PARAMS:
        raw = get.get(key)
        if raw:
            found[key] = _truncate(raw.strip(), 255)
    return found


def get_session_utm(session) -> dict[str, str]:
    stored = session.get(UTM_SESSION_KEY) or {}
    return {k: stored[k] for k in UTM_PARAMS if stored.get(k)}


def store_session_utm(session, utm: dict[str, str]) -> None:
    if not utm:
        return
    existing = dict(session.get(UTM_SESSION_KEY) or {})
    existing.update(utm)
    session[UTM_SESSION_KEY] = existing
    session.modified = True


def should_track_request(request) -> bool:
    if request.method != "GET":
        return False
    if request.headers.get("X-Requested-With") == "XMLHttpRequest":
        return False
    path = request.path or "/"
    if any(path.startswith(prefix) for prefix in SKIP_PREFIXES):
        return False
    match = getattr(request, "resolver_match", None)
    if match and match.url_name in SKIP_NAMES:
        return False
    accept = request.headers.get("Accept", "")
    if accept and "text/html" not in accept and "*/*" not in accept:
        return False
    return True


def record_page_visit(request) -> PageVisit | None:
    if not should_track_request(request):
        return None

    landing_utm = extract_utm_from_get(request.GET)
    if landing_utm:
        store_session_utm(request.session, landing_utm)

    attribution = landing_utm or get_session_utm(request.session)
    user_agent = _truncate(request.META.get("HTTP_USER_AGENT", ""), 512)
    referrer = _truncate(request.META.get("HTTP_REFERER", ""), 1024)
    session_key = ""
    if hasattr(request, "session"):
        # Ensure session exists so return visits can keep first-touch UTM.
        if not request.session.session_key:
            request.session.save()
        session_key = request.session.session_key or ""

    try:
        return PageVisit.objects.create(
            path=_truncate(request.path or "/", 512),
            query_string=_truncate(request.META.get("QUERY_STRING", ""), 1024),
            referrer=referrer,
            user_agent=user_agent,
            traffic_type=classify_user_agent(user_agent),
            utm_source=attribution.get("utm_source", ""),
            utm_medium=attribution.get("utm_medium", ""),
            utm_campaign=attribution.get("utm_campaign", ""),
            utm_term=attribution.get("utm_term", ""),
            utm_content=attribution.get("utm_content", ""),
            session_key=session_key,
            is_landing=bool(landing_utm),
        )
    except (OperationalError, IntegrityError):
        # Avoid breaking page loads if DB is unavailable or migration pending.
        return None


class UTMTrackingMiddleware:
    """Record HTML GET page views after the view runs successfully."""

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        if 200 <= response.status_code < 300:
            content_type = response.get("Content-Type", "")
            if not content_type or "text/html" in content_type:
                record_page_visit(request)
        return response
