"""角色脑的结构化输出 schema(pydantic;走 LLM 的 with_structured_output,免脆弱正则)。

每个决策点一个 schema。day_speech 顺带产出 reads[] —— agent 对各人的最新判断,回写主观对局板。
"""

from __future__ import annotations

from typing import List, Optional

from pydantic import BaseModel, Field


class WolfDiscussOut(BaseModel):
    target: int = Field(description="你提议今晚刀的座位号")
    message: str = Field(default="", description="给狼队友的一句话(私聊频道,只有狼看得到)")


class NightKillOut(BaseModel):
    target: int = Field(description="今晚狼队要刀的座位号")
    reason: str = Field(default="", description="简短理由")


class NightCheckOut(BaseModel):
    target: int = Field(description="今晚要查验的座位号")
    reason: str = Field(default="", description="为什么查这个人")


class WitchOut(BaseModel):
    save: bool = Field(default=False, description="是否用解药救今晚刀口")
    poison_target: Optional[int] = Field(default=None, description="要毒的座位号;不毒填 null")
    reason: str = Field(default="", description="简短理由")


class RunSheriffOut(BaseModel):
    run: bool = Field(description="是否上警竞选警长")
    reason: str = Field(default="", description="简短理由")


class SpeechDirOut(BaseModel):
    direction: str = Field(default="cw",
                           description="发言方向:cw=从你左手边(座位顺位)起 | ccw=从你右手边(逆位)起;你自己压轴最后发言")
    reason: str = Field(default="", description="简短理由")


class WithdrawOut(BaseModel):
    withdraw: bool = Field(default=False, description="是否退水(退出警长竞选)")
    reason: str = Field(default="", description="简短理由")


class BadgePassOut(BaseModel):
    target: Optional[int] = Field(default=None, description="把警徽移交给的座位号;撕毁警徽填 null")
    reason: str = Field(default="", description="简短理由")


class ExplodeOut(BaseModel):
    explode: bool = Field(default=False, description="是否现在自爆(白天掀桌亮狼身份,中止当天发言投票直接入夜);极少用,只在关键时刻")
    reason: str = Field(default="", description="简短理由")


class ReadOut(BaseModel):
    seat: int = Field(description="被你判断的座位号")
    judgment: str = Field(default="unknown", description="good | wolf | unknown")
    confidence: float = Field(default=0.0, description="0~1 的置信")
    claim: str = Field(default="", description="该玩家自报的身份(若有)")


class SpeechOut(BaseModel):
    # 刻意保持"扁平"(无嵌套列表):MiniMax 对嵌套结构常吐空函数调用导致失败。
    # 主观对局板的更新由 accuse 派生 + 各 agent 每轮重读 transcript 推理(跨人信息靠公共发言)。
    speech_text: str = Field(description="你这一轮的口语发言(一段话)")
    claim_role: str = Field(default="", description="你自报的身份;不跳身份填空")
    accuse: Optional[int] = Field(default=None, description="你重点指认/最怀疑是狼的座位号")
    vote_intent: Optional[int] = Field(default=None, description="你打算投谁出局")
    stance: str = Field(default="", description="你的站边/归票倾向(一句话)")


class VoteOut(BaseModel):
    target: Optional[int] = Field(default=None, description="投谁出局;弃票填 null")
    reason: str = Field(default="", description="简短理由")


class HunterShootOut(BaseModel):
    target: Optional[int] = Field(default=None, description="开枪带走谁;放弃填 null")
    reason: str = Field(default="", description="简短理由")


class DayDigestOut(BaseModel):
    # 每天收尾的"局记"压缩(扁平,稳):双层——key_facts 铁的客观事实(累积保留,别丢旧的)+ notes 滚动主观分析。
    key_facts: str = Field(
        default="",
        description="【铁的事实·累积更新别丢旧的】客观线索清单(简短分点):死亡名单+你推断的死法(刀/毒/枪/放逐)、"
                    "谁公开自报了什么身份/谁对跳谁、公开的查验结果、警长是谁、明显的票型异常(谁救谁/谁带头投谁)。只记事实,不下判断。")
    notes: str = Field(
        description="【主观分析·滚动重写】基于事实,几句话:你各人的好狼判断与理由、当前阵营局势、你下一步计划(在旧 notes 上更新,别太长)")
    prime_suspect: Optional[int] = Field(default=None, description="你现在最怀疑是狼的座位号")
    most_trusted: Optional[int] = Field(default=None, description="你现在最信任(像好人)的座位号")


class RecallOut(BaseModel):
    # 发言前的"要不要查原文":给一个 query(座位号 / 'day:N' / 关键词);不需要就留空。
    query: str = Field(default="", description="想查阅的原始记录:某座位号、'day:2'、或一个关键词;不需要查就留空")
