from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, Field

from app.schemas.ontology import OntologyParseResult

UserAgentCitationType = Literal["rule", "knowledge"]


class UserAgentCitation(BaseModel):
    source_type: UserAgentCitationType = Field(description="引用来源类型。")
    code: str = Field(description="来源编码。")
    title: str = Field(description="来源标题。")
    version: str | None = Field(default=None, description="引用版本。")
    updated_at: str | None = Field(default=None, description="来源更新时间。")
    excerpt: str | None = Field(default=None, description="面向用户展示的引用摘要。")


class UserAgentSuggestedAction(BaseModel):
    label: str = Field(description="建议动作文案。")
    action_type: str = Field(description="动作类型，例如 open_detail / create_draft。")
    description: str = Field(default="", description="动作说明。")
    payload: dict[str, Any] = Field(default_factory=dict, description="动作携带的结构化参数。")


class UserAgentDraftPayload(BaseModel):
    draft_type: str = Field(description="草稿类型。")
    title: str = Field(description="草稿标题。")
    body: str = Field(description="草稿正文。")
    confirmation_required: bool = Field(default=True, description="是否需要人工确认。")
    claim_id: str | None = Field(default=None, description="关联的报销草稿 ID。")
    claim_no: str | None = Field(default=None, description="关联的报销草稿单号。")
    status: str | None = Field(default=None, description="当前报销草稿状态。")
    approval_stage: str | None = Field(default=None, description="当前审批节点。")


class UserAgentQueryStatusGroup(BaseModel):
    key: str = Field(description="状态分组键名。")
    label: str = Field(description="状态分组展示名。")
    count: int = Field(default=0, ge=0, description="该分组单据数。")


class UserAgentExpenseQueryRecord(BaseModel):
    claim_id: str = Field(description="报销单主键。")
    claim_no: str = Field(description="报销单号。")
    employee_name: str = Field(default="", description="申请人。")
    expense_type: str = Field(default="", description="费用类型编码。")
    expense_type_label: str = Field(default="", description="费用类型中文名。")
    amount: float = Field(default=0.0, ge=0.0, description="金额。")
    status: str = Field(default="", description="单据状态编码。")
    status_label: str = Field(default="", description="单据状态中文名。")
    status_group: str = Field(default="", description="状态分组编码。")
    status_group_label: str = Field(default="", description="状态分组中文名。")
    approval_stage: str | None = Field(default=None, description="审批节点。")
    document_date: str = Field(default="", description="用于近 10 日展示的单据日期。")
    occurred_at: str = Field(default="", description="业务发生日期。")
    reason: str = Field(default="", description="事由。")
    location: str = Field(default="", description="地点。")
    risk_flags: list[dict[str, Any]] = Field(default_factory=list, description="该单据当前风险项。")


class UserAgentQueryPayload(BaseModel):
    result_type: str = Field(default="expense_claim_list", description="结构化查询结果类型。")
    title: str = Field(default="", description="查询结果标题。")
    scope_label: str = Field(default="报销单", description="当前查询范围名。")
    recent_window_applied: bool = Field(default=False, description="是否应用了近 10 日窗口。")
    window_days: int | None = Field(default=None, ge=1, description="近 N 日窗口天数。")
    window_start_date: str | None = Field(default=None, description="近 N 日窗口开始日期。")
    window_end_date: str | None = Field(default=None, description="近 N 日窗口结束日期。")
    record_count: int = Field(default=0, ge=0, description="当前展示范围内的单据数。")
    preview_count: int = Field(default=0, ge=0, description="当前返回的单据数。")
    preview_limit: int = Field(default=5, ge=1, description="默认展示条数上限。")
    older_record_count: int = Field(default=0, ge=0, description="超出近 10 日窗口的单据数。")
    has_more_in_window: bool = Field(default=False, description="当前展示范围内是否还有更多单据未返回。")
    total_amount: float = Field(default=0.0, ge=0.0, description="当前展示范围内金额合计。")
    status_groups: list[UserAgentQueryStatusGroup] = Field(
        default_factory=list,
        description="当前展示范围内的状态分组统计。",
    )
    records: list[UserAgentExpenseQueryRecord] = Field(
        default_factory=list,
        description="当前返回的单据列表。",
    )


class UserAgentReviewRiskBrief(BaseModel):
    title: str = Field(description="风险或注意事项标题。")
    level: str = Field(default="info", description="级别，例如 info / warning / high。")
    content: str = Field(description="面向用户展示的摘要说明。")
    detail: str = Field(default="", description="点击风险项后展示的详细解释。")
    suggestion: str = Field(default="", description="面向用户的处理建议。")


class UserAgentReviewSlotCard(BaseModel):
    key: str = Field(description="槽位键名。")
    label: str = Field(description="槽位展示名。")
    value: str = Field(default="", description="当前识别值。")
    raw_value: str = Field(default="", description="原始识别文本。")
    normalized_value: str = Field(default="", description="标准化后的字段值。")
    source: str = Field(default="system", description="字段来源，例如 user_text / ocr / page_context。")
    source_label: str = Field(default="系统判断", description="字段来源中文名。")
    confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="识别置信度。")
    required: bool = Field(default=True, description="是否为关键字段。")
    confirmed: bool = Field(default=False, description="是否可视为已确认。")
    status: str = Field(default="identified", description="identified / inferred / missing。")
    hint: str = Field(default="", description="字段补充提示。")
    evidence: str = Field(default="", description="字段识别依据。")


class UserAgentReviewDocumentField(BaseModel):
    label: str = Field(description="字段名。")
    value: str = Field(default="", description="字段值。")
    source: str = Field(default="ocr", description="字段来源。")


class UserAgentReviewDocumentCard(BaseModel):
    index: int = Field(description="票据顺序号，从 1 开始。")
    filename: str = Field(description="原始文件名。")
    document_type: str = Field(default="other", description="票据候选类型。")
    suggested_expense_type: str = Field(default="other", description="建议归属费用类型。")
    scene_label: str = Field(default="", description="面向用户展示的票据类型标签。")
    summary: str = Field(default="", description="逐票据摘要。")
    avg_score: float = Field(default=0.0, ge=0.0, le=1.0, description="OCR 平均得分。")
    preview_kind: str = Field(default="", description="票据预览类型，例如 image。")
    preview_data_url: str = Field(default="", description="票据预览图片 data URL。")
    preview_url: str = Field(default="", description="票据预览图片地址。")
    warnings: list[str] = Field(default_factory=list, description="该票据的识别提示。")
    fields: list[UserAgentReviewDocumentField] = Field(
        default_factory=list,
        description="逐票据关键字段。",
    )


class UserAgentReviewClaimGroup(BaseModel):
    group_code: str = Field(description="候选报销组编码。")
    title: str = Field(description="候选报销组标题。")
    expense_type: str = Field(description="归属费用类型编码。")
    scene_label: str = Field(description="归属费用类型名称。")
    document_indexes: list[int] = Field(default_factory=list, description="挂入该组的票据序号。")
    amount_total: float = Field(default=0.0, ge=0.0, description="该组候选金额。")
    rationale: str = Field(default="", description="为什么建议这样分组。")


class UserAgentReviewAction(BaseModel):
    label: str = Field(description="动作名称。")
    action_type: str = Field(description="动作类型。")
    description: str = Field(default="", description="动作说明。")
    emphasis: str = Field(default="secondary", description="primary / secondary / warning。")


class UserAgentReviewEditField(BaseModel):
    key: str = Field(description="编辑字段键名。")
    label: str = Field(description="编辑字段展示名。")
    value: str = Field(default="", description="当前字段值。")
    placeholder: str = Field(default="", description="输入占位提示。")
    required: bool = Field(default=True, description="是否必填。")
    field_type: str = Field(default="text", description="text / textarea。")
    group: str = Field(default="basic", description="字段分组。")


class UserAgentReviewPayload(BaseModel):
    intent_summary: str = Field(description="系统对本次报销意图的结构化摘要。")
    body_message: str = Field(default="", description="正文区的简洁提示。")
    scenario: str = Field(description="当前场景。")
    intent: str = Field(description="当前意图。")
    can_proceed: bool = Field(default=False, description="当前是否满足进入下一步的前置条件。")
    missing_slots: list[str] = Field(default_factory=list, description="当前仍缺失的关键槽位。")
    risk_briefs: list[UserAgentReviewRiskBrief] = Field(
        default_factory=list,
        description="历史风险和当前注意事项。",
    )
    slot_cards: list[UserAgentReviewSlotCard] = Field(
        default_factory=list,
        description="待确认槽位卡片。",
    )
    document_cards: list[UserAgentReviewDocumentCard] = Field(
        default_factory=list,
        description="逐票据识别卡片。",
    )
    claim_groups: list[UserAgentReviewClaimGroup] = Field(
        default_factory=list,
        description="候选报销分单建议。",
    )
    confirmation_actions: list[UserAgentReviewAction] = Field(
        default_factory=list,
        description="面向前端渲染的确认动作卡片。",
    )
    edit_fields: list[UserAgentReviewEditField] = Field(
        default_factory=list,
        description="用户修改识别结果时使用的预填字段模板。",
    )


class UserAgentRequest(BaseModel):
    run_id: str = Field(description="关联的 AgentRun.run_id。")
    user_id: str | None = Field(default=None, description="当前请求用户 ID。")
    message: str = Field(description="原始用户问题。")
    ontology: OntologyParseResult = Field(description="语义解析结果。")
    context_json: dict[str, Any] = Field(default_factory=dict, description="附加上下文。")
    tool_payload: dict[str, Any] = Field(default_factory=dict, description="工具返回的原始结果。")
    selected_capability_codes: list[str] = Field(
        default_factory=list,
        description="本次命中的能力编码。",
    )
    degraded: bool = Field(default=False, description="当前是否发生降级。")
    requires_confirmation: bool = Field(default=False, description="是否要求确认。")


class UserAgentResponse(BaseModel):
    answer: str = Field(description="面向用户展示的自然语言回答。")
    citations: list[UserAgentCitation] = Field(default_factory=list, description="规则或知识引用。")
    suggested_actions: list[UserAgentSuggestedAction] = Field(
        default_factory=list,
        description="建议的下一步动作。",
    )
    query_payload: UserAgentQueryPayload | None = Field(
        default=None,
        description="结构化查询结果，用于前端渲染真实单据列表。",
    )
    draft_payload: UserAgentDraftPayload | None = Field(default=None, description="可选草稿内容。")
    review_payload: UserAgentReviewPayload | None = Field(
        default=None,
        description="结构化预审结果，用于前端确认面板。",
    )
    risk_flags: list[str] = Field(default_factory=list, description="本次回答关联的风险标签。")
    requires_confirmation: bool = Field(default=False, description="是否需要人工确认。")
