"""Proactive reflection — avoid repeats, continue yesterday, hold_back."""

from __future__ import annotations

import re
from dataclasses import dataclass
from typing import Any, Literal

from pathlib import Path

from niannian.chat.proactive_profile import save_proactive_profile
from niannian.chat.proactive_scope import ProactiveScope
from niannian.virtual_persona.assembly_master import (
    PROACTIVE_ASSEMBLY_EXCERPT_MAX,
    read_assembly_master,
    truncate_assembly_excerpt,
)
from niannian.virtual_persona.store import VirtualPersonaStore

ReflectIntent = Literal["hold_back", "continue_yesterday", "gentle_checkin", "new_angle"]

_REPEAT_PATTERNS = (
    r"上次聊过了",
    r"说过了",
    r"别说了",
    r"知道了",
    r"别再提",
    r"already talked",
)


@dataclass(frozen=True)
class ReflectBrief:
    intent: ReflectIntent
    topic: str
    reason: str
    confidence: float
    assembly_excerpt: str = ""


def detect_repeat_phrase(user_text: str) -> bool:
    text = (user_text or "").strip()
    if not text:
        return False
    for pat in _REPEAT_PATTERNS:
        if re.search(pat, text, re.IGNORECASE):
            return True
    return False


def _topic_in_avoid(topic: str, avoid_topics: list[Any]) -> bool:
    t = (topic or "").strip().lower()
    if not t:
        return False
    for item in avoid_topics:
        if not isinstance(item, str):
            continue
        if item.strip().lower() in t or t in item.strip().lower():
            return True
    return False


def record_repeat_feedback(
    scope: ProactiveScope,
    profile: dict[str, Any],
    *,
    topic: str,
) -> dict[str, Any]:
    """User said 'talked already' — update scope profile, never subject."""
    updated = dict(profile)
    avoid = list(updated.get("avoid_topics") or [])
    label = (topic or "recent_topic").strip() or "recent_topic"
    if label not in avoid:
        avoid.append(label)
    updated["avoid_topics"] = avoid[-20:]
    mult = float(updated.get("interval_multiplier") or 1.0)
    updated["interval_multiplier"] = min(mult + 0.15, 2.5)
    updated["ignored_streak"] = int(updated.get("ignored_streak") or 0) + 1
    save_proactive_profile(scope, updated)
    return updated


def load_proactive_assembly_excerpt(
    home: Path,
    user_id: str,
    vp_id: str | None,
    *,
    max_chars: int = PROACTIVE_ASSEMBLY_EXCERPT_MAX,
) -> tuple[str, list[str]]:
    """Load truncated assembly_master for equipped VP proactive turns."""
    if not vp_id:
        return "", []
    store = VirtualPersonaStore(home, user_id)
    raw = read_assembly_master(store, vp_id).strip()
    if not raw:
        return "", []
    excerpt = truncate_assembly_excerpt(raw, max_chars=max_chars)
    return excerpt, [f"proactive assembly_excerpt {len(excerpt)} chars"]


def build_reflect_brief(
    scope: ProactiveScope,
    *,
    candidate_topic: str,
    profile: dict[str, Any],
    open_threads: list[dict[str, Any]] | None = None,
    unfinished_yesterday: bool = False,
    assembly_excerpt: str = "",
) -> ReflectBrief:
    avoid = profile.get("avoid_topics") or []
    topic = (candidate_topic or "").strip() or "general"

    excerpt = truncate_assembly_excerpt(assembly_excerpt)

    if _topic_in_avoid(topic, avoid):
        return ReflectBrief(
            intent="hold_back",
            topic=topic,
            reason="avoid_topics",
            confidence=0.9,
            assembly_excerpt=excerpt,
        )

    threads = open_threads or []
    for th in threads:
        if not isinstance(th, dict):
            continue
        theme = str(th.get("theme") or "")
        if unfinished_yesterday and theme:
            return ReflectBrief(
                intent="continue_yesterday",
                topic=theme,
                reason="open_thread_yesterday",
                confidence=0.75,
                assembly_excerpt=excerpt,
            )

    if unfinished_yesterday:
        return ReflectBrief(
            intent="continue_yesterday",
            topic=topic,
            reason="unfinished_session",
            confidence=0.65,
            assembly_excerpt=excerpt,
        )

    if scope.chat_mode == "companion":
        return ReflectBrief(
            intent="gentle_checkin",
            topic=topic,
            reason="companion_mode",
            confidence=0.6,
            assembly_excerpt=excerpt,
        )

    return ReflectBrief(
        intent="new_angle",
        topic=topic,
        reason="default",
        confidence=0.55,
        assembly_excerpt=excerpt,
    )
