"""Advertisement routes.

A single public click-through endpoint records the click and forwards the user
to the advertisement's destination. Serving/selection happens in templates via
the ``active_ads`` context processor; this route only handles outbound clicks so
they can be counted.
"""

from __future__ import annotations

from urllib.parse import urlparse

from flask import redirect, url_for

from app.advertisements import advertisements_bp
from app.advertisements.services import (
    get_advertisement_or_404,
    record_click,
    record_impressions,
)


def _safe_external_url(raw: str | None) -> str | None:
    """Allow only http(s) absolute URLs (block javascript:, data:, etc.)."""
    if not raw:
        return None
    parsed = urlparse(raw)
    if parsed.scheme in ("http", "https") and parsed.netloc:
        return raw
    return None


@advertisements_bp.route("/<public_id>/click")
def click(public_id: str):
    """Record a click for an advertisement and redirect to its destination."""
    ad = get_advertisement_or_404(public_id)
    record_click(ad)
    destination = _safe_external_url(ad.redirect_url)
    return redirect(destination or url_for("main.landing"))


@advertisements_bp.route("/<public_id>/impression")
def impression(public_id: str):
    """Record a single impression (analytics beacon fired when an ad is shown).

    Fire-and-forget: reuses the shared ``record_impressions`` helper and returns an
    empty 204 so client JS can call it without handling a body. GET mirrors the
    click route so no CSRF token is required for this best-effort counter.
    """
    ad = get_advertisement_or_404(public_id)
    record_impressions([ad])
    return "", 204
