"""Random temporal recall lens — year/month/day/hour, not fixed windows."""

from __future__ import annotations

import random
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from typing import Any, Literal

TemporalGranularity = Literal["hour", "day", "month", "season", "year"]

_SEASON_KEYWORDS = frozenset({"夏天", "夏季", "夏日", "冬天", "冬季", "春天", "春季", "秋天", "秋季"})
_BASE_WEIGHTS: dict[TemporalGranularity, float] = {
    "hour": 1.0,
    "day": 1.2,
    "month": 1.0,
    "season": 0.8,
    "year": 0.6,
}


@dataclass(frozen=True)
class TemporalLens:
    granularity: TemporalGranularity
    start: datetime
    end: datetime

    def to_range(self, now: datetime | None = None) -> tuple[datetime, datetime]:
        return self.start, self.end


def _season_bounds(now: datetime) -> tuple[datetime, datetime]:
    month = now.month
    if month in (6, 7, 8):
        start = now.replace(month=6, day=1, hour=0, minute=0, second=0, microsecond=0)
        end = now.replace(month=8, day=31, hour=23, minute=59, second=59, microsecond=0)
    elif month in (12, 1, 2):
        start = now.replace(month=12, day=1, hour=0, minute=0, second=0, microsecond=0)
        if month == 1 or month == 2:
            start = start.replace(year=now.year - 1)
        end = start.replace(month=2, day=28, hour=23, minute=59, second=59)
    elif month in (3, 4, 5):
        start = now.replace(month=3, day=1, hour=0, minute=0, second=0, microsecond=0)
        end = now.replace(month=5, day=31, hour=23, minute=59, second=59, microsecond=0)
    else:
        start = now.replace(month=9, day=1, hour=0, minute=0, second=0, microsecond=0)
        end = now.replace(month=11, day=30, hour=23, minute=59, second=59, microsecond=0)
    return start, end


def _lens_bounds(granularity: TemporalGranularity, now: datetime) -> tuple[datetime, datetime]:
    if granularity == "hour":
        return now - timedelta(hours=2), now + timedelta(hours=2)
    if granularity == "day":
        start = now.replace(hour=0, minute=0, second=0, microsecond=0)
        return start - timedelta(days=1), start + timedelta(days=1, hours=23, minutes=59)
    if granularity == "month":
        start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        prev = (start - timedelta(days=1)).replace(day=1)
        return prev, start + timedelta(days=32)
    if granularity == "season":
        return _season_bounds(now)
    # year
    start = now.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
    return start.replace(year=now.year - 1), now


def _context_boosts(context_text: str) -> dict[TemporalGranularity, float]:
    text = (context_text or "").lower()
    boosts = {g: 1.0 for g in _BASE_WEIGHTS}
    if any(k in context_text for k in _SEASON_KEYWORDS) or "summer" in text:
        boosts["season"] = 2.5
        boosts["year"] = 1.4
    if any(k in context_text for k in ("昨天", "今早", "刚才", "刚刚")):
        boosts["day"] = 2.0
        boosts["hour"] = 1.5
    if any(k in context_text for k in ("买", "购物", "衣服", "新")):
        boosts["month"] = 1.8
        boosts["day"] = 1.3
    return boosts


def sample_temporal_lens(
    *,
    context_text: str = "",
    profile: dict[str, Any] | None = None,
    now: datetime | None = None,
    rng: random.Random | None = None,
) -> TemporalLens:
    """Weighted-random pick of recall time lens."""
    r = rng or random.Random()
    now = now or datetime.now(timezone.utc)
    boosts = _context_boosts(context_text)
    profile_bias = (profile or {}).get("learned_lens_bias") or {}
    weights: list[float] = []
    keys: list[TemporalGranularity] = []
    for g in _BASE_WEIGHTS:
        w = _BASE_WEIGHTS[g] * boosts[g] * float(profile_bias.get(g, 1.0))
        weights.append(max(w, 0.01))
        keys.append(g)
    granularity = r.choices(keys, weights=weights, k=1)[0]
    start, end = _lens_bounds(granularity, now)
    return TemporalLens(granularity=granularity, start=start, end=end)
