from __future__ import annotations

from datetime import datetime
from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field

from app.core.agent_enums import (
    AgentAssetContentType,
    AgentAssetDomain,
    AgentAssetStatus,
    AgentAssetType,
    AgentReviewStatus,
)


class AgentAssetCreate(BaseModel):
    scope: Literal["tenant", "platform"] = "tenant"
    asset_type: AgentAssetType
    code: str = Field(min_length=1, max_length=100)
    name: str = Field(min_length=1, max_length=200)
    description: str = ""
    domain: AgentAssetDomain
    scenario_json: list[Any] = Field(default_factory=list)
    owner: str = Field(min_length=1, max_length=100)
    reviewer: str | None = Field(default=None, max_length=100)
    status: AgentAssetStatus = AgentAssetStatus.DRAFT
    config_json: dict[str, Any] = Field(default_factory=dict)


class AgentAssetUpdate(BaseModel):
    name: str | None = Field(default=None, min_length=1, max_length=200)
    description: str | None = None
    domain: AgentAssetDomain | None = None
    scenario_json: list[Any] | None = None
    owner: str | None = Field(default=None, min_length=1, max_length=100)
    reviewer: str | None = Field(default=None, max_length=100)
    status: AgentAssetStatus | None = None
    current_version: str | None = Field(default=None, max_length=30)
    published_version: str | None = Field(default=None, max_length=30)
    working_version: str | None = Field(default=None, max_length=30)
    config_json: dict[str, Any] | None = None


class AgentAssetVersionCreate(BaseModel):
    version: str = Field(min_length=1, max_length=30)
    content: Any
    content_type: AgentAssetContentType
    change_note: str | None = None
    created_by: str = Field(min_length=1, max_length=100)


class RuleMarkdownUpdate(BaseModel):
    version: str = Field(min_length=1, max_length=30)
    content: str
    change_note: str | None = None
    created_by: str = Field(min_length=1, max_length=100)


class AgentAssetReviewCreate(BaseModel):
    version: str = Field(min_length=1, max_length=30)
    reviewer: str = Field(min_length=1, max_length=100)
    review_status: AgentReviewStatus
    review_note: str | None = None


class AgentAssetReviewRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    tenant_id: str
    scope: str
    asset_id: str
    version: str
    reviewer: str
    review_status: str
    review_note: str | None
    reviewed_at: datetime | None
    created_at: datetime


class AgentAssetOnlyOfficeConfigRead(BaseModel):
    documentServerUrl: str
    config: dict[str, Any] = Field(default_factory=dict)


class AgentAssetOnlyOfficeCallbackRead(BaseModel):
    error: int = 0


class AgentAssetOnlyOfficeCallbackWrite(BaseModel):
    model_config = ConfigDict(extra="allow")

    status: int = Field(description="ONLYOFFICE 回调状态码。")
    url: str | None = Field(default=None, description="文档下载地址，状态为 2 或 6 时使用。")
    key: str | None = Field(default=None, description="ONLYOFFICE 当前文档会话 key。")
    users: list[str] = Field(default_factory=list, description="当前编辑用户列表。")


class AgentAssetRuleJsonWrite(BaseModel):
    payload: dict[str, Any] = Field(default_factory=dict)


class AgentAssetRuleJsonRead(BaseModel):
    file_name: str
    rule_code: str
    name: str
    description: str = ""
    evaluator: str = ""
    ontology_signal: str | None = None
    flow_diagram_svg: str | None = None
    inputs: dict[str, Any] = Field(default_factory=dict)
    outcomes: dict[str, Any] = Field(default_factory=dict)
    payload: dict[str, Any] = Field(default_factory=dict)


class AgentAssetRiskRuleGenerateRequest(BaseModel):
    business_domain: AgentAssetDomain = AgentAssetDomain.EXPENSE
    business_stage: str | None = Field(
        default="reimbursement",
        pattern="^(expense_application|reimbursement)$",
        max_length=40,
    )
    expense_category: str | None = Field(default=None, max_length=40)
    rule_title: str | None = Field(default=None, max_length=80)
    risk_level: str | None = Field(default=None, pattern="^(low|medium|high|critical)$")
    natural_language: str = Field(min_length=8, max_length=2000)
    requires_attachment: bool = False


class AgentAssetRiskRuleDraftUpdate(BaseModel):
    rule_title: str | None = Field(default=None, min_length=2, max_length=80)
    expense_category: str | None = Field(default=None, max_length=40)
    natural_language: str | None = Field(default=None, min_length=8, max_length=2000)
    requires_attachment: bool | None = None


class AgentAssetRiskRuleRevisionCreate(BaseModel):
    rule_title: str | None = Field(default=None, min_length=2, max_length=80)
    expense_category: str | None = Field(default=None, max_length=40)
    natural_language: str | None = Field(default=None, min_length=8, max_length=2000)
    requires_attachment: bool | None = None
    change_reason: str = Field(min_length=1, max_length=1000)


class AgentAssetRiskRuleRegenerateRequest(BaseModel):
    rule_title: str | None = Field(default=None, min_length=2, max_length=80)
    expense_category: str | None = Field(default=None, max_length=40)
    natural_language: str | None = Field(default=None, min_length=8, max_length=2000)
    requires_attachment: bool | None = None


class AgentAssetRiskRuleTemplateFieldRead(BaseModel):
    key: str
    label: str
    display: str
    source: str
    type: str


class AgentAssetRiskRuleTemplateRead(BaseModel):
    template_id: str
    group: str
    group_label: str
    title: str
    description: str = ""
    business_domain: str = "expense"
    business_stage: str = "reimbursement"
    business_stage_label: str = "费用报销"
    expense_category: str | None = None
    expense_category_label: str = ""
    requires_attachment: bool = False
    natural_language: str
    fields: list[AgentAssetRiskRuleTemplateFieldRead] = Field(default_factory=list)
    dsl_example: dict[str, Any] = Field(default_factory=dict)


class AgentAssetRiskRuleTemplateGroupRead(BaseModel):
    group: str
    group_label: str
    order: int
    templates: list[AgentAssetRiskRuleTemplateRead] = Field(default_factory=list)


class AgentAssetRiskRuleSampleCase(BaseModel):
    case_id: str | None = Field(default=None, max_length=60)
    name: str = Field(default="测试样例", min_length=1, max_length=80)
    values: dict[str, Any] = Field(default_factory=dict)
    expected_hit: bool = True
    expected_severity: str | None = Field(default=None, max_length=20)
    note: str | None = None


class AgentAssetRiskRuleSampleTestRequest(BaseModel):
    version: str | None = Field(default=None, max_length=30)
    cases: list[AgentAssetRiskRuleSampleCase] = Field(default_factory=list)


class AgentAssetRiskRuleScenarioTestRequest(BaseModel):
    target_tenant_id: str = Field(min_length=1, max_length=64)
    version: str | None = Field(default=None, max_length=30)
    intent: str = Field(default="", max_length=1000)
    filters: dict[str, Any] = Field(default_factory=dict)


class AgentAssetRiskRuleReportRequest(BaseModel):
    version: str | None = Field(default=None, max_length=30)
    confirm_passed: bool = True
    note: str | None = Field(default=None, max_length=1000)


class GoldenCaseCreate(BaseModel):
    case_key: str = Field(..., max_length=160)
    rule_code: str | None = Field(default=None, max_length=120)
    scene: str = Field(default="", max_length=50)
    name: str = Field(default="", max_length=120)
    values: dict[str, Any] = Field(default_factory=dict)
    expected_hit: bool = True
    expected_severity: str | None = Field(default=None, max_length=20)
    note: str | None = None


class GoldenCaseRead(BaseModel):
    id: str
    case_key: str
    rule_code: str | None = None
    scene: str = ""
    name: str = ""
    values: dict[str, Any] = Field(default_factory=dict)
    expected_hit: bool = True
    expected_severity: str | None = None
    note: str | None = None
    status: str = "active"
    source: str = "manual"


class GoldenEvalRequest(BaseModel):
    version: str | None = Field(default=None, max_length=30)


class GoldenEvalRead(BaseModel):
    total: int = 0
    passed_count: int = 0
    failed_count: int = 0
    accuracy: float = 0.0
    precision: float = 0.0
    recall: float = 0.0
    all_passed: bool = True
    results: list[dict[str, Any]] = Field(default_factory=list)


class AgentAssetRiskRuleSimulationAttachment(BaseModel):
    name: str = Field(default="", max_length=240)
    content_type: str | None = Field(default=None, max_length=120)
    size: int | None = Field(default=None, ge=0)
    note: str | None = Field(default=None, max_length=500)
    ocr_text: str | None = Field(default=None, max_length=20000)
    summary: str | None = Field(default=None, max_length=2000)
    document_type: str | None = Field(default=None, max_length=80)
    document_type_label: str | None = Field(default=None, max_length=120)
    scene_code: str | None = Field(default=None, max_length=80)
    scene_label: str | None = Field(default=None, max_length=120)
    avg_score: float | None = Field(default=None, ge=0.0, le=1.0)
    recognition_status: str | None = Field(default=None, max_length=40)
    document_fields: list[dict[str, Any]] = Field(default_factory=list)


class AgentAssetRiskRuleSimulationRequest(BaseModel):
    version: str | None = Field(default=None, max_length=30)
    message: str = Field(default="", max_length=4000)
    field_values: dict[str, Any] = Field(default_factory=dict)
    attachments: list[AgentAssetRiskRuleSimulationAttachment] = Field(default_factory=list)


class AgentAssetRiskRuleSimulationRead(BaseModel):
    version: str
    ready: bool = True
    stage: str = "executed"
    hit: bool
    severity: str = "none"
    severity_label: str = "未命中"
    summary: str
    blocking_reason: str = ""
    message: str = ""
    field_values: dict[str, Any] = Field(default_factory=dict)
    normalized_fields: dict[str, Any] = Field(default_factory=dict)
    evidence: dict[str, Any] = Field(default_factory=dict)
    trace: dict[str, Any] = Field(default_factory=dict)
    attachments: list[dict[str, Any]] = Field(default_factory=list)
    recognized_fields: list[dict[str, Any]] = Field(default_factory=list)
    ocr_raw_fields: list[dict[str, Any]] = Field(default_factory=list)
    hermes_normalized_fields: list[dict[str, Any]] = Field(default_factory=list)
    executor_input_fields: list[dict[str, Any]] = Field(default_factory=list)
    missing_fields: list[dict[str, Any]] = Field(default_factory=list)
    recognition_summary: list[dict[str, Any]] = Field(default_factory=list)
    execution_mode: str = "risk_rule_simulation"
    created_at: datetime


class AgentAssetRiskRuleReturnRequest(BaseModel):
    note: str = Field(min_length=1, max_length=1000)


class AgentAssetRiskRuleEnabledUpdate(BaseModel):
    enabled: bool


class AgentAssetRiskRuleLevelUpdate(BaseModel):
    risk_level: str = Field(pattern="^(low|medium|high|critical)$")


class AgentAssetRiskRuleFeedbackCreate(BaseModel):
    version: str | None = Field(default=None, max_length=30)
    feedback_type: str = Field(pattern="^(false_positive|false_negative|unclear|improvement)$")
    subject_type: str | None = Field(default=None, max_length=50)
    subject_key: str | None = Field(default=None, max_length=160)
    subject_label: str | None = Field(default=None, max_length=200)
    actual_result: dict[str, Any] = Field(default_factory=dict)
    expected_result: dict[str, Any] = Field(default_factory=dict)
    comment: str = Field(min_length=1, max_length=1000)
    payload: dict[str, Any] = Field(default_factory=dict)


class AgentAssetRiskRuleFeedbackRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    tenant_id: str
    scope: str
    feedback_id: str
    asset_id: str
    version: str
    feedback_type: str
    status: str
    subject_type: str = ""
    subject_key: str = ""
    subject_label: str = ""
    actual_result_json: dict[str, Any] = Field(default_factory=dict)
    expected_result_json: dict[str, Any] = Field(default_factory=dict)
    comment: str | None = None
    payload_json: dict[str, Any] = Field(default_factory=dict)
    created_by: str
    created_at: datetime


class AgentAssetRiskRuleTestRunRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    tenant_id: str
    scope: str
    asset_id: str
    version: str
    test_type: str
    status: str
    passed: bool
    summary: str
    input_json: dict[str, Any] = Field(default_factory=dict)
    result_json: dict[str, Any] = Field(default_factory=dict)
    created_by: str
    created_at: datetime


class AgentAssetRiskRuleLatestTestSummary(BaseModel):
    version: str = ""
    sample: AgentAssetRiskRuleTestRunRead | None = None
    scenario: AgentAssetRiskRuleTestRunRead | None = None
    report: AgentAssetRiskRuleTestRunRead | None = None
    test_passed: bool = False


class AgentAssetVersionTimelineItemRead(BaseModel):
    event_type: str
    version: str
    actor: str
    event_time: datetime
    title: str
    description: str = ""
    note: str | None = None
    source_version: str | None = None


class AgentAssetSpreadsheetDiffCellRead(BaseModel):
    sheet_name: str
    cell: str
    change_type: str
    before_value: Any | None = None
    after_value: Any | None = None


class AgentAssetSpreadsheetDiffSheetRead(BaseModel):
    sheet_name: str
    change_type: str


class AgentAssetSpreadsheetChangeRecordRead(BaseModel):
    id: str
    actor: str
    changed_at: datetime
    summary: str
    sheet_changes: list[AgentAssetSpreadsheetDiffSheetRead] = Field(default_factory=list)
    cell_changes: list[AgentAssetSpreadsheetDiffCellRead] = Field(default_factory=list)
    changed_sheet_count: int = 0
    changed_cell_count: int = 0


class AgentAssetVersionRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    tenant_id: str
    scope: str
    asset_id: str
    version: str
    content: Any
    content_type: str
    change_note: str | None
    created_by: str
    created_at: datetime
    is_current: bool = False
    is_published: bool = False
    is_working: bool = False
    lifecycle_state: str = "history"


class AgentAssetListItem(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    tenant_id: str
    scope: str
    asset_type: str
    code: str
    name: str
    description: str
    domain: str
    scenario_json: list[Any]
    owner: str
    reviewer: str | None
    status: str
    current_version: str | None
    published_version: str | None
    working_version: str | None
    config_json: dict[str, Any]
    change_count: int = 0
    modified_by: str | None = None
    published_by: str | None = None
    published_at: datetime | None = None
    created_at: datetime
    updated_at: datetime


class AgentAssetRead(AgentAssetListItem):
    current_version_content: Any | None = None
    current_version_content_type: str | None = None
    current_version_change_note: str | None = None
    recent_versions: list[AgentAssetVersionRead] = Field(default_factory=list)
    latest_review: AgentAssetReviewRead | None = None
    latest_test_summary: AgentAssetRiskRuleLatestTestSummary | None = None
