from __future__ import annotations

from datetime import UTC, date, datetime, timedelta
from typing import Literal

FreshnessStatus = Literal["fresh", "stale", "partial", "unavailable", "unknown"]

# A single, deliberately conservative read-model threshold. It is evaluated against
# source as_of, never against the request or local render time.
DEFAULT_FRESHNESS_MAX_AGE = timedelta(days=2)


def parse_source_time(value: str | None) -> datetime | None:
    """Parse a source date/time as UTC without substituting a receive time."""
    if not value:
        return None
    raw = value.strip()
    try:
        if len(raw) == 10:
            return datetime.combine(date.fromisoformat(raw), datetime.min.time(), tzinfo=UTC)
        parsed = datetime.fromisoformat(raw.replace("Z", "+00:00"))
    except ValueError:
        return None
    return parsed.replace(tzinfo=UTC) if parsed.tzinfo is None else parsed.astimezone(UTC)


def freshness_status(
    *,
    available: bool,
    as_of: str | None,
    now: datetime | None = None,
    max_age: timedelta = DEFAULT_FRESHNESS_MAX_AGE,
) -> FreshnessStatus:
    if not available:
        return "unavailable"
    source_time = parse_source_time(as_of)
    if source_time is None:
        return "unknown"
    reference = now or datetime.now(UTC)
    reference = reference.replace(tzinfo=UTC) if reference.tzinfo is None else reference.astimezone(UTC)
    return "stale" if reference - source_time > max_age else "fresh"


def combined_freshness(statuses: list[FreshnessStatus]) -> FreshnessStatus:
    """Collapse read-model sources without claiming availability that is absent."""
    present = [status for status in statuses if status != "unavailable"]
    if not present:
        return "unavailable"
    if len(present) != len(statuses) or "partial" in present:
        return "partial"
    if "stale" in present:
        return "stale"
    if "unknown" in present:
        return "unknown"
    return "fresh"
