from __future__ import annotations

from typing import Literal

from pydantic import BaseModel, Field

Scene = Literal["feed", "push", "widget"]


class ScoreConfig(BaseModel):
    """
    打分配置（可调参）。

    说明：
    - 默认值由 `defaults.get_default_config(scene)` 提供
    - 本模块不负责回退梯度（fallback_level）策略；仅做防御式 clamp
    """

    w_need: float
    w_emotion: float
    w_stage: float
    w_context: float

    alpha: float = 0.15
    beta: float = 0.30

    enable_uncertainty_penalty: bool = False

    # Widget 情绪软区间与软降权强度
    widget_emotion_soft_range: tuple[float, float] = (0.4, 0.8)
    widget_emotion_penalty_gamma: float = 0.25


class ExternalTerms(BaseModel):
    """
    外部注入项（V1 可选）。

    说明：
    - 由 `rerank-freqcap` 或 `reco-engine` 产出
    - 本模块缺省按 0，保证可排序与输出结构稳定
    """

    S_fresh: float = 0.0
    P_fatigue: float = 0.0
    P_repeat: float = 0.0
    P_risk: float = 0.0


class ScoreBreakdown(BaseModel):
    """
    可观测分解项（用于调参与回归测试）。
    """

    scene: Scene
    passed: bool = Field(alias="pass")

    missing_fields: list[str] = Field(default_factory=list)

    S_need: float
    S_context: float
    S_stage: float
    S_emotion: float

    S_core: float
    S_personal: float
    S_fresh: float

    P_fatigue: float
    P_repeat: float
    P_risk: float
    P_uncertainty: float

    # Widget 专用：区间外软降权（建议保留，便于打点）
    P_widget_emotion_out_of_range: float = 0.0

    model_config = {
        "populate_by_name": True,
    }


class ScoreResult(BaseModel):
    final_score: float
    breakdown: ScoreBreakdown

