"""P15/P16 proactive correction — preferred intent after user feedback."""

from __future__ import annotations

from dataclasses import dataclass, replace
from typing import Any

from niannian.chat.proactive_reflect import ReflectBrief, ReflectIntent
from niannian.chat.proactive_scope import ProactivePersonaPolicy

P16_PLANE_ID = "P16"


@dataclass(frozen=True)
class IntentCandidate:
    intent: ReflectIntent
    topic: str
    confidence: float
    source: str  # p15 | reflect


@dataclass(frozen=True)
class CorrectionResult:
    preferred_intent: ReflectIntent
    topic: str
    hold_back: bool
    tone_bias: str
    assembly_excerpt: str = ""
    skill_block: str = ""
    trace: tuple[str, ...] = ()


def p15_reflect_candidates(reflect_brief: ReflectBrief) -> list[IntentCandidate]:
    """小意 — rule-based candidate intents from reflect brief."""
    primary = IntentCandidate(
        intent=reflect_brief.intent,
        topic=reflect_brief.topic,
        confidence=reflect_brief.confidence,
        source="reflect",
    )
    alts: list[IntentCandidate] = []
    if reflect_brief.intent != "gentle_checkin":
        alts.append(
            IntentCandidate(
                intent="gentle_checkin",
                topic=reflect_brief.topic,
                confidence=max(0.3, reflect_brief.confidence - 0.15),
                source="p15",
            )
        )
    if reflect_brief.intent != "new_angle":
        alts.append(
            IntentCandidate(
                intent="new_angle",
                topic=reflect_brief.topic,
                confidence=max(0.25, reflect_brief.confidence - 0.2),
                source="p15",
            )
        )
    return [primary, *alts]


def p16_correct(
    candidates: list[IntentCandidate],
    profile: dict[str, Any],
    vp_policy: ProactivePersonaPolicy | None = None,
) -> CorrectionResult:
    """小审 — user corrections + VP curves → final intent."""
    if not candidates:
        return CorrectionResult(
            preferred_intent="hold_back",
            topic="",
            hold_back=True,
            tone_bias="quiet",
        )

    best = max(candidates, key=lambda c: c.confidence)
    hold_back = best.intent == "hold_back"

    ignored = int(profile.get("ignored_streak") or 0)
    explicit = int(profile.get("explicit_bias") or 0)
    disturb = str(profile.get("proactive_disturb_lock") or "auto")

    if ignored >= 2 or explicit <= -1 or disturb == "quiet":
        hold_back = True
        best = next((c for c in candidates if c.intent == "hold_back"), best)

    if vp_policy and vp_policy.interruptiveness < 0.4 and best.intent in ("gentle_checkin", "continue_yesterday"):
        if ignored >= 1 or explicit <= 0:
            hold_back = True

    tone = "warm"
    if vp_policy:
        if vp_policy.interruptiveness < 0.4:
            tone = "cool"
        elif vp_policy.clinginess > 0.8:
            tone = "warm"
    if hold_back:
        tone = "quiet"

    intent = "hold_back" if hold_back else best.intent
    return CorrectionResult(
        preferred_intent=intent,
        topic=best.topic,
        hold_back=hold_back,
        tone_bias=tone,
    )
