from __future__ import annotations

import json
from dataclasses import dataclass
from datetime import date
from typing import Any

from app.schemas.steward import StewardPlanRequest
from app.services.ontology_field_registry import normalize_ontology_form_values
from app.services.runtime_chat import RuntimeChatService
from app.services.steward_intent_registry import (
    all_flow_ids,
    all_task_types,
    all_intents,
)


STEWARD_INTENT_FUNCTION_NAME = "submit_steward_intent_plan"


def _build_supported_intent_summary() -> str:
    """从注册表拼接当前支持的意图列表,供 system prompt 引用。"""
    fragments = [f"{desc.task_type}（{desc.label}）" for desc in all_intents()]
    return "、".join(fragments) if fragments else "（暂无已注册意图）"


def _build_intent_prompt_fragments() -> str:
    """从注册表拼接每个意图的识别指引片段。"""
    fragments = [desc.prompt_fragment for desc in all_intents() if desc.prompt_fragment]
    if not fragments:
        return ""
    return "".join(fragments)


@dataclass(frozen=True, slots=True)
class StewardIntentAgentResult:
    payload: dict[str, Any]
    model_call_traces: list[dict[str, Any]]


class StewardIntentAgent:
    """使用大模型 function calling 识别小财管家的复合财务意图。"""

    def __init__(self, runtime_chat_service: RuntimeChatService) -> None:
        self.runtime_chat_service = runtime_chat_service
        self.last_call_traces: list[dict[str, Any]] = []

    def detect(
        self,
        request: StewardPlanRequest,
        *,
        base_date: date,
        canonical_fields: list[str],
    ) -> StewardIntentAgentResult | None:
        result = self.runtime_chat_service.complete_with_tool_call(
            self._build_messages(request, base_date=base_date, canonical_fields=canonical_fields),
            tools=[self._build_intent_tool_schema(canonical_fields)],
            tool_choice={
                "type": "function",
                "function": {"name": STEWARD_INTENT_FUNCTION_NAME},
            },
            max_tokens=1800,
            temperature=0.1,
            timeout_seconds=10,
            max_attempts=3,
            use_failure_cooldown=False,
        )
        self.last_call_traces = result.calls_as_dicts()
        if result.tool_call is None or result.tool_call.name != STEWARD_INTENT_FUNCTION_NAME:
            return None
        return StewardIntentAgentResult(
            payload=result.tool_call.arguments,
            model_call_traces=self.last_call_traces,
        )

    @staticmethod
    def _build_messages(
        request: StewardPlanRequest,
        *,
        base_date: date,
        canonical_fields: list[str],
    ) -> list[dict[str, Any]]:
        context_payload = {
            "message": request.message,
            "base_date": base_date.isoformat(),
            "client_now_iso": request.client_now_iso,
            "user_id": request.user_id,
            "canonical_ontology_fields": canonical_fields,
            "review_form_values": normalize_ontology_form_values(
                request.context_json.get("review_form_values")
            ),
            "context_json": {
                key: value
                for key, value in request.context_json.items()
                if key
                in {
                    "entry_source",
                    "session_type",
                    "role_codes",
                    "username",
                    "name",
                    "department_name",
                    "employee_grade",
                    "employee_no",
                    "client_timezone_offset_minutes",
                    "recent_history",
                }
            },
            "recent_history": [
                {
                    "role": str(item.get("role") or "").strip(),
                    "content": str(item.get("content") or "").strip(),
                }
                for item in (request.context_json.get("recent_history") or [])
                if isinstance(item, dict) and str(item.get("content") or "").strip()
            ],
            "attachments": [
                {
                    "index": index + 1,
                    "name": item.name,
                    "media_type": item.media_type,
                    "ocr_summary": item.ocr_summary,
                    "ocr_fields": item.ocr_fields,
                }
                for index, item in enumerate(request.attachments)
                if item.name
            ],
        }
        return [
            {
                "role": "system",
                "content": (
                    "你是 X-Financial 的小财管家意图识别智能体。"
                    "你必须通过 function calling 输出结构化计划，不能只返回普通文本。"
                    f"当前支持的 task_type 包括：{_build_supported_intent_summary()}。"
                    "你只做识别、拆解、归集和确认点规划，不能执行入库、绑定附件或提交审批。"
                    f"{_build_intent_prompt_fragments()}"
                    "如果用户只描述出差时间、地点和事由，但没有明确申请、报销、提交、保存草稿等动作，"
                    "且无法从上下文判断流程方向，必须返回 pending_flow_confirmation.status=pending，"
                    "candidate_flows 同时给出 travel_application 和 travel_reimbursement，tasks 保持空数组。"
                    "所有 ontology_fields 只能使用调用方给出的 canonical_ontology_fields；"
                    "如果输入里出现 occurred_date、transport_type、reason_value 等别名，必须映射为 canonical 字段。"
                    "每个 task 必须输出 requested_action：用户只是要求整理/发起但未说保存或提交时为 preview；"
                    "用户说保存草稿、先保存、存草稿时为 save_draft；用户说直接提交、提交申请、确认提交时为 submit。"
                    "对于查询类任务(如查询差旅标准),requested_action 固定为 preview。"
                    "recent_history 是本会话最近 10 轮对话（role 为 user 或 assistant）。"
                    "当用户说“再提交”“继续”“重新提交”“重新申请”等确认类话术时，"
                    "必须结合 recent_history 里最近一次提到的出差/报销申请来理解用户意图，"
                    "复用该申请的 ontology_fields 重新生成 task，而不是把确认话术当作孤立的模糊输入。"
                    "如果 recent_history 为空或无法关联到具体申请，才按当前 message 字面理解。"
                    "相对日期必须以 base_date 为准转换为明确日期。"
                    "thinking_events 只能是面向用户的过程摘要，不能暴露内部推理链。"
                    "如果用户输入与出差、费用、报销、申请、差旅标准等财务事项完全无关"
                    "（例如纯数字、问候、闲聊、无意义字符、单字符重复），"
                    "必须让 tasks 返回空数组，并在 thinking_events 中明确说明“未识别到财务事项”。"
                ),
            },
            {
                "role": "user",
                "content": json.dumps(context_payload, ensure_ascii=False),
            },
        ]

    @staticmethod
    def _build_intent_tool_schema(canonical_fields: list[str]) -> dict[str, Any]:
        return {
            "type": "function",
            "function": {
                "name": STEWARD_INTENT_FUNCTION_NAME,
                "description": "提交小财管家的复合财务意图识别结果。",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "thinking_events": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "stage": {"type": "string"},
                                    "title": {"type": "string"},
                                    "content": {"type": "string"},
                                },
                                "required": ["stage", "title", "content"],
                            },
                        },
                        "tasks": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "task_type": {
                                        "type": "string",
                                        "enum": all_task_types(),
                                    },
                                    "title": {"type": "string"},
                                    "summary": {"type": "string"},
                                    "confidence": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 1,
                                    },
                                    "requested_action": {
                                        "type": "string",
                                        "enum": ["preview", "save_draft", "submit"],
                                    },
                                    "ontology_fields": {
                                        "type": "object",
                                        "additionalProperties": {"type": "string"},
                                    },
                                    "missing_fields": {
                                        "type": "array",
                                        "items": {
                                            "type": "string",
                                            "enum": canonical_fields,
                                        },
                                    },
                                },
                                "required": [
                                    "task_type",
                                    "title",
                                    "summary",
                                    "confidence",
                                    "requested_action",
                                    "ontology_fields",
                                    "missing_fields",
                                ],
                            },
                        },
                        "pending_flow_confirmation": {
                            "type": "object",
                            "properties": {
                                "status": {
                                    "type": "string",
                                    "enum": ["none", "pending"],
                                },
                                "source_message": {"type": "string"},
                                "reason": {"type": "string"},
                                "candidate_flows": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "properties": {
                                            "flow_id": {
                                                "type": "string",
                                                "enum": all_flow_ids(),
                                            },
                                            "label": {"type": "string"},
                                            "confidence": {
                                                "type": "number",
                                                "minimum": 0,
                                                "maximum": 1,
                                            },
                                            "reason": {"type": "string"},
                                            "ontology_fields": {
                                                "type": "object",
                                                "additionalProperties": {"type": "string"},
                                            },
                                            "missing_fields": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string",
                                                    "enum": canonical_fields,
                                                },
                                            },
                                        },
                                        "required": [
                                            "flow_id",
                                            "label",
                                            "confidence",
                                            "reason",
                                            "ontology_fields",
                                            "missing_fields",
                                        ],
                                    },
                                },
                            },
                            "required": ["status", "source_message", "reason", "candidate_flows"],
                        },
                        "attachment_groups": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "target_task_index": {
                                        "type": "integer",
                                        "minimum": 1,
                                    },
                                    "scene": {"type": "string"},
                                    "scene_label": {"type": "string"},
                                    "attachment_names": {
                                        "type": "array",
                                        "items": {"type": "string"},
                                    },
                                    "excluded_attachment_names": {
                                        "type": "array",
                                        "items": {"type": "string"},
                                    },
                                    "confidence": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 1,
                                    },
                                    "rationale": {"type": "string"},
                                },
                                "required": [
                                    "scene",
                                    "scene_label",
                                    "attachment_names",
                                    "excluded_attachment_names",
                                    "confidence",
                                    "rationale",
                                ],
                            },
                        },
                    },
                    "required": ["thinking_events", "tasks", "attachment_groups"],
                },
            },
        }
