from __future__ import annotations

import re
from datetime import UTC, datetime
from typing import Any

from sqlalchemy import select
from sqlalchemy.orm import Session

from app.api.deps import CurrentUserContext
from app.core.agent_enums import (
    AgentAssetStatus,
    AgentAssetType,
    AgentName,
    AgentPermissionLevel,
    AgentRunSource,
    AgentRunStatus,
)
from app.core.logging import get_logger
from app.models.tenant import Tenant
from app.schemas.agent_asset import AgentAssetListItem, AgentAssetRead
from app.schemas.ontology import OntologyParseRequest, OntologyParseResult
from app.schemas.orchestrator import (
    OrchestratorRequest,
    OrchestratorResponse,
    OrchestratorTraceSummary,
)
from app.schemas.user_agent import UserAgentRequest
from app.services.agent_assets import AgentAssetService
from app.services.agent_conversations import AgentConversationService
from app.services.agent_foundation import AgentFoundationService
from app.services.agent_runs import AgentRunService
from app.services.agent_traces import AgentTraceService
from app.services.auth import AuthService
from app.services.expense_claims import ExpenseClaimService
from app.services.ontology import SemanticOntologyService
from app.services.orchestrator_execution import ExecutionOutcome, OrchestratorExecutionEngine
from app.services.orchestrator_expense_application_workflow import (
    OrchestratorExpenseApplicationWorkflow,
)
from app.services.orchestrator_expense_query import OrchestratorDatabaseQueryBuilder
from app.services.user_agent import UserAgentService
from app.services.user_agent_application import (
    APPLICATION_CONTEXT_VALUES,
    APPLICATION_SHORT_CONFIRMATIONS,
    APPLICATION_SUBMIT_KEYWORDS,
)

logger = get_logger("app.services.orchestrator")

SCENARIO_TO_DOMAIN = {
    "expense": "expense",
    "accounts_receivable": "ar",
    "accounts_payable": "ap",
    "knowledge": "knowledge",
    "unknown": "system",
}


class OrchestratorService:
    def __init__(self, db: Session) -> None:
        self.db = db
        self.asset_service = AgentAssetService(db)
        self.conversation_service = AgentConversationService(db)
        self.expense_claim_service = ExpenseClaimService(db)
        self.knowledge_service = None
        self.run_service = AgentRunService(db)
        self.trace_service = AgentTraceService(db)
        self.ontology_service = SemanticOntologyService(db)
        self.user_agent_service = UserAgentService(db)
        self.expense_application_workflow = OrchestratorExpenseApplicationWorkflow(db)
        self.database_query_builder = OrchestratorDatabaseQueryBuilder(db)
        self.execution_engine = OrchestratorExecutionEngine(
            db=db,
            run_service=self.run_service,
            expense_claim_service=self.expense_claim_service,
            knowledge_service=self.knowledge_service,
            user_agent_service=self.user_agent_service,
            database_query_builder=self.database_query_builder,
            trace_service=self.trace_service,
        )

    def run(
        self,
        payload: OrchestratorRequest,
        *,
        current_user: CurrentUserContext | None = None,
        trusted_tenant_id: str | None = None,
    ) -> OrchestratorResponse:
        tenant_id = self._resolve_trusted_tenant_id(
            current_user=current_user,
            trusted_tenant_id=trusted_tenant_id,
        )
        if current_user is not None:
            payload = self._build_authenticated_user_payload(payload, current_user)
        else:
            payload = payload.model_copy(
                update={
                    "context_json": {
                        **dict(payload.context_json or {}),
                        "tenant_id": tenant_id,
                    }
                }
            )
        AgentFoundationService(self.db).ensure_foundation_ready()
        context_json = self._hydrate_user_context(
            user_id=payload.user_id,
            context_json=dict(payload.context_json or {}),
        )
        conversation_id = str(payload.conversation_id or "").strip() or None
        conversation = None
        if payload.source == AgentRunSource.USER_MESSAGE.value:
            conversation = self.conversation_service.get_or_create_conversation(
                conversation_id=conversation_id,
                user_id=payload.user_id,
                source=payload.source,
                context_json=context_json,
            )
            conversation_id = conversation.conversation_id
            context_json = self.conversation_service.hydrate_context_json(
                conversation=conversation,
                context_json=context_json,
                message=payload.message,
            )
            context_json["conversation_id"] = conversation_id
        elif conversation_id:
            context_json["conversation_id"] = conversation_id

        route_json: dict[str, Any] = {
            "orchestrated_by": AgentName.ORCHESTRATOR.value,
            "stage": "created",
        }
        if conversation_id:
            route_json["conversation_id"] = conversation_id
        route_json["tenant_id"] = tenant_id
        run = self.run_service.create_run(
            agent=AgentName.ORCHESTRATOR.value,
            source=payload.source,
            tenant_id=tenant_id,
            user_id=payload.user_id,
            task_id=payload.task_id,
            ontology_json={},
            route_json=route_json,
            permission_level=AgentPermissionLevel.READ.value,
            status=AgentRunStatus.RUNNING.value,
            result_summary="Orchestrator 已接收请求。",
        )
        self._record_trace_event(
            run_id=run.run_id,
            conversation_id=conversation_id,
            stage="orchestrator",
            event_name="request_received",
            title="接收用户请求",
            summary=str(payload.message or payload.task_id or payload.source or "").strip(),
            input_json={
                "source": payload.source,
                "user_id": payload.user_id,
                "conversation_id": conversation_id,
                "task_id": payload.task_id,
                "message": payload.message,
            },
            output_json={
                "run_id": run.run_id,
                "context_keys": sorted(context_json.keys()),
            },
        )

        try:
            message, task_asset = self._resolve_message(payload)
            if conversation is not None:
                self.conversation_service.append_message(
                    conversation_id=conversation.conversation_id,
                    role="user",
                    content=message,
                    run_id=run.run_id,
                    message_json={
                        "attachment_names": context_json.get("attachment_names", []),
                        "attachment_count": context_json.get("attachment_count", 0),
                        "ocr_summary": context_json.get("ocr_summary", ""),
                    },
                )
                self._record_trace_event(
                    run_id=run.run_id,
                    conversation_id=conversation.conversation_id,
                    stage="conversation",
                    event_name="conversation_hydrated",
                    title="会话上下文补全",
                    summary=f"会话 {conversation.conversation_id} 已写入用户消息。",
                    input_json={"message": message},
                    output_json={
                        "conversation_id": conversation.conversation_id,
                        "context_keys": sorted(context_json.keys()),
                    },
                )
            ontology = self.ontology_service.parse_for_run(
                OntologyParseRequest(
                    query=message,
                    user_id=payload.user_id,
                    context_json=context_json,
                ),
                run_id=run.run_id,
            )
            self._record_trace_event(
                run_id=run.run_id,
                conversation_id=conversation_id,
                stage="semantic",
                event_name="semantic_parsed",
                title="语义识别完成",
                summary=f"{ontology.scenario} / {ontology.intent}",
                input_json={"query": message, "context_keys": sorted(context_json.keys())},
                output_json=self.execution_engine._build_ontology_json(ontology),
            )
            if context_json.get("simulate_orchestrator_exception"):
                raise RuntimeError("simulated orchestrator exception")
            selected_agent, route_reason = self._select_agent(payload, ontology)
            capabilities = self._select_capabilities(
                payload=payload,
                ontology=ontology,
                task_asset=task_asset,
            )
            selected_capability_codes = self.execution_engine._flatten_capability_codes(
                capabilities
            )
            is_expense_review_action = self.execution_engine._is_expense_review_action(context_json)
            is_expense_application_context = self._is_expense_application_context(context_json)
            requires_confirmation = (
                ontology.permission.level == AgentPermissionLevel.APPROVAL_REQUIRED.value
                and not is_expense_review_action
                and not is_expense_application_context
            )
            self._record_trace_event(
                run_id=run.run_id,
                conversation_id=conversation_id,
                stage="route",
                event_name="route_resolved",
                title="路由与能力选择",
                summary=route_reason,
                input_json={
                    "scenario": ontology.scenario,
                    "intent": ontology.intent,
                    "permission_level": ontology.permission.level,
                },
                output_json={
                    "selected_agent": selected_agent,
                    "route_reason": route_reason,
                    "selected_capability_codes": selected_capability_codes,
                    "requires_confirmation": requires_confirmation,
                },
            )

            route_json = {
                "orchestrated_by": AgentName.ORCHESTRATOR.value,
                "stage": "routed",
                "selected_agent": selected_agent,
                "route_reason": route_reason,
                "selected_capability_codes": selected_capability_codes,
                "ontology_run_id": ontology.run_id,
            }
            route_json["tenant_id"] = tenant_id
            if task_asset is not None:
                task_config = task_asset.config_json or {}
                route_json["job_type"] = str(task_config.get("task_type") or "").strip()
                route_json["task_code"] = task_asset.code
                route_json["task_name"] = task_asset.name

            authenticated_application_outcome = None
            if (
                is_expense_application_context
                and current_user is not None
                and ontology.permission.level != AgentPermissionLevel.FORBIDDEN.value
            ):
                authenticated_application_outcome = self.expense_application_workflow.execute(
                    payload=payload,
                    current_user=current_user,
                    run_id=run.run_id,
                    conversation_id=conversation_id,
                    ontology=ontology,
                    context_json=context_json,
                    selected_capability_codes=selected_capability_codes,
                )

            if ontology.permission.level == AgentPermissionLevel.FORBIDDEN.value:
                outcome = ExecutionOutcome(
                    status=AgentRunStatus.BLOCKED.value,
                    result={
                        "message": ontology.permission.reason,
                        "clarification_question": ontology.clarification_question,
                        "degraded": False,
                    },
                    degraded=False,
                    tool_count=0,
                    failed_tool_count=0,
                )
                selected_agent = None
                route_reason = "permission_forbidden"
                route_json["stage"] = "blocked"
                route_json["route_reason"] = route_reason
            elif authenticated_application_outcome is not None:
                outcome = authenticated_application_outcome
                route_reason = "authenticated_application_preview_workflow"
                route_json["stage"] = "application_preview_workflow"
                route_json["route_reason"] = route_reason
            elif ontology.clarification_required:
                if selected_agent == AgentName.USER_AGENT.value and ontology.scenario == "expense":
                    clarification_response = self.user_agent_service.respond(
                        UserAgentRequest(
                            run_id=run.run_id,
                            user_id=payload.user_id,
                            message=payload.message or "",
                            ontology=ontology,
                            context_json=context_json,
                            tool_payload={"clarification_required": True},
                            selected_capability_codes=selected_capability_codes,
                            degraded=False,
                            requires_confirmation=requires_confirmation,
                        )
                    )
                    clarification_result = self.execution_engine._build_user_agent_result(
                        clarification_response,
                        degraded=False,
                    )
                    clarification_result.update(
                        {
                            "clarification_required": True,
                            "missing_slots": ontology.missing_slots,
                            "ambiguity": ontology.ambiguity,
                            "parse_strategy": ontology.parse_strategy,
                        }
                    )
                    clarification_status = (
                        AgentRunStatus.SUCCEEDED.value
                        if self._is_application_submit_result(clarification_result)
                        else AgentRunStatus.BLOCKED.value
                    )
                    if clarification_status == AgentRunStatus.SUCCEEDED.value:
                        clarification_result["clarification_required"] = False
                        clarification_result["missing_slots"] = []
                    outcome = ExecutionOutcome(
                        status=clarification_status,
                        result=clarification_result,
                        degraded=False,
                        tool_count=0,
                        failed_tool_count=0,
                    )
                else:
                    outcome = ExecutionOutcome(
                        status=AgentRunStatus.BLOCKED.value,
                        result={
                            "message": ontology.clarification_question or "需要补充更多上下文。",
                            "clarification_required": True,
                            "missing_slots": ontology.missing_slots,
                            "ambiguity": ontology.ambiguity,
                            "parse_strategy": ontology.parse_strategy,
                            "degraded": False,
                        },
                        degraded=False,
                        tool_count=0,
                        failed_tool_count=0,
                    )
                route_reason = "clarification_required"
                route_json["stage"] = "clarification"
                route_json["route_reason"] = route_reason
            elif selected_agent == AgentName.HERMES.value:
                outcome = self.execution_engine._execute_hermes(
                    payload=payload,
                    run_id=run.run_id,
                    ontology=ontology,
                    capabilities=capabilities,
                    requires_confirmation=requires_confirmation,
                    task_asset=task_asset,
                    context_json=context_json,
                )
            else:
                outcome = self.execution_engine._execute_user_agent(
                    payload=payload,
                    run_id=run.run_id,
                    ontology=ontology,
                    capabilities=capabilities,
                    requires_confirmation=requires_confirmation,
                    context_json=context_json,
                )

            result_requires_confirmation = bool(outcome.result.get("requires_confirmation"))
            response_requires_confirmation = requires_confirmation or (
                is_expense_application_context and result_requires_confirmation
            )
            final_status = (
                AgentRunStatus.BLOCKED.value
                if outcome.status == AgentRunStatus.SUCCEEDED.value
                and (
                    (
                        requires_confirmation
                        and ontology.permission.level
                        == AgentPermissionLevel.APPROVAL_REQUIRED.value
                    )
                    or (is_expense_application_context and result_requires_confirmation)
                )
                else outcome.status
            )
            response_status = self._normalize_response_status(final_status)
            result_message = (
                str(outcome.result.get("message", "")).strip() or "Orchestrator 执行完成。"
            )
            trace_summary = OrchestratorTraceSummary(
                scenario=ontology.scenario,
                intent=ontology.intent,
                tool_count=outcome.tool_count,
                failed_tool_count=outcome.failed_tool_count,
                selected_capability_codes=selected_capability_codes,
                degraded=outcome.degraded,
            )
            self.run_service.update_run(
                run.run_id,
                agent=selected_agent or AgentName.ORCHESTRATOR.value,
                ontology_json=self.execution_engine._build_ontology_json(ontology),
                route_json={
                    **route_json,
                    "requires_confirmation": response_requires_confirmation,
                    "degraded": outcome.degraded,
                },
                permission_level=ontology.permission.level,
                status=final_status,
                result_summary=result_message,
                error_message=None,
                finished_at=datetime.now(UTC),
            )
            if conversation is not None and conversation_id:
                draft_payload = outcome.result.get("draft_payload")
                self.conversation_service.update_state(
                    conversation_id=conversation_id,
                    run_id=run.run_id,
                    scenario=ontology.scenario,
                    intent=ontology.intent,
                    context_json=context_json,
                    draft_payload=draft_payload if isinstance(draft_payload, dict) else None,
                )
                self.conversation_service.append_message(
                    conversation_id=conversation_id,
                    role="assistant",
                    content=result_message,
                    run_id=run.run_id,
                    message_json={
                        "status": final_status,
                        "scenario": ontology.scenario,
                        "intent": ontology.intent,
                        "attachment_names": context_json.get("attachment_names", []),
                        "attachment_count": context_json.get("attachment_count", 0),
                        "draft_payload": draft_payload if isinstance(draft_payload, dict) else None,
                        "orchestrator_payload": {
                            "run_id": run.run_id,
                            "conversation_id": conversation_id,
                            "selected_agent": selected_agent,
                            "route_reason": route_reason,
                            "permission_level": ontology.permission.level,
                            "status": response_status,
                            "requires_confirmation": response_requires_confirmation,
                            "trace_summary": trace_summary.model_dump(),
                            "result": outcome.result,
                        },
                    },
                )
                self._record_trace_event(
                    run_id=run.run_id,
                    conversation_id=conversation_id,
                    stage="conversation",
                    event_name="conversation_updated",
                    title="会话状态写回",
                    summary="助手回复与会话状态已写回。",
                    input_json={"draft_payload_present": isinstance(draft_payload, dict)},
                    output_json={"status": final_status, "message": result_message},
                )
            self._record_trace_event(
                run_id=run.run_id,
                conversation_id=conversation_id,
                stage="response",
                event_name="response_built",
                title="生成最终回复",
                status=final_status,
                summary=result_message,
                input_json={"outcome_status": outcome.status},
                output_json={
                    "status": response_status,
                    "requires_confirmation": response_requires_confirmation,
                    "trace_summary": trace_summary.model_dump(),
                    "result": outcome.result,
                },
            )
            return OrchestratorResponse(
                run_id=run.run_id,
                conversation_id=conversation_id,
                selected_agent=selected_agent,
                route_reason=route_reason,
                permission_level=ontology.permission.level,
                status=response_status,
                result=outcome.result,
                requires_confirmation=response_requires_confirmation,
                trace_summary=trace_summary,
            )
        except Exception as exc:
            logger.exception("Orchestrator run failed run_id=%s", run.run_id)
            self._record_trace_event(
                run_id=run.run_id,
                conversation_id=conversation_id,
                stage="orchestrator",
                event_name="failed",
                title="Orchestrator 执行失败",
                status="failed",
                summary=str(exc),
                output_json={"route_json": route_json},
                error_message=str(exc),
            )
            self.run_service.update_run(
                run.run_id,
                agent=AgentName.ORCHESTRATOR.value,
                route_json={**route_json, "stage": "failed"},
                status=AgentRunStatus.FAILED.value,
                result_summary="Orchestrator 执行失败。",
                error_message=str(exc),
                finished_at=datetime.now(UTC),
            )
            if conversation is not None and conversation_id:
                self.conversation_service.update_state(
                    conversation_id=conversation_id,
                    run_id=run.run_id,
                    scenario=None,
                    intent=None,
                    context_json=context_json,
                    draft_payload=None,
                )
                self.conversation_service.append_message(
                    conversation_id=conversation_id,
                    role="assistant",
                    content=f"Orchestrator 执行失败：{exc}",
                    run_id=run.run_id,
                    message_json={"status": AgentRunStatus.FAILED.value},
                )
            return OrchestratorResponse(
                run_id=run.run_id,
                conversation_id=conversation_id,
                selected_agent=None,
                route_reason="orchestrator_exception",
                permission_level=AgentPermissionLevel.READ.value,
                status="failed",
                result={"message": f"Orchestrator 执行失败：{exc}"},
                requires_confirmation=False,
                trace_summary=OrchestratorTraceSummary(
                    scenario="unknown",
                    intent="query",
                    tool_count=0,
                    failed_tool_count=0,
                    selected_capability_codes=[],
                    degraded=False,
                ),
            )

    @staticmethod
    def _build_authenticated_user_payload(
        payload: OrchestratorRequest,
        current_user: CurrentUserContext,
    ) -> OrchestratorRequest:
        """用登录态覆盖所有身份字段，并丢弃客户端伪造的可信预览状态。"""
        context_json = dict(payload.context_json or {})
        for key in (
            "application_preview",
            "application_preview_decision",
            "decision_id",
            "preview_decision_id",
            "auth_session_id",
            "requested_by_username",
            "requested_by_name",
            "actor",
            "actor_id",
        ):
            context_json.pop(key, None)
        context_json.update(
            {
                "tenant_id": current_user.tenant_id,
                "role_codes": list(current_user.role_codes),
                "is_admin": current_user.is_admin,
                "username": current_user.username,
                "user_id": current_user.username,
                "name": current_user.name,
                "department": current_user.department_name,
                "department_name": current_user.department_name,
                "cost_center": current_user.cost_center,
                "position": current_user.position,
                "grade": current_user.grade,
                "employee_no": current_user.employee_no,
                "employee_id": current_user.employee_id,
                "manager_name": current_user.manager_name,
                "requested_by_username": current_user.username,
                "requested_by_name": current_user.name,
                "actor": current_user.username,
                "actor_id": current_user.username,
            }
        )
        return payload.model_copy(
            update={
                "user_id": current_user.username,
                "context_json": context_json,
            }
        )

    def _resolve_trusted_tenant_id(
        self,
        *,
        current_user: CurrentUserContext | None,
        trusted_tenant_id: str | None,
    ) -> str:
        user_tenant = str(current_user.tenant_id or "").strip() if current_user is not None else ""
        internal_tenant = str(trusted_tenant_id or "").strip()
        if user_tenant and internal_tenant and user_tenant != internal_tenant:
            raise ValueError("登录用户租户与内部任务租户不一致。")
        if user_tenant:
            return user_tenant
        if not internal_tenant:
            raise ValueError("Orchestrator 缺少可信租户上下文。")
        registered = self.db.scalar(
            select(Tenant.tenant_id).where(
                Tenant.tenant_id == internal_tenant,
                Tenant.status == "active",
            )
        )
        if registered is None:
            raise ValueError("Orchestrator 内部任务租户不存在或未启用。")
        return internal_tenant

    def _record_trace_event(self, **kwargs: Any) -> None:
        self.trace_service.record_event_safe(**kwargs)

    def _hydrate_user_context(
        self,
        user_id: str | None,
        context_json: dict[str, Any],
    ) -> dict[str, Any]:
        identifier = str(
            user_id or context_json.get("username") or context_json.get("email") or ""
        ).strip()
        if not identifier:
            return context_json

        tenant_id = str(context_json.get("tenant_id") or "").strip()
        if not tenant_id:
            return context_json
        snapshot = AuthService(self.db).get_user_snapshot(
            identifier,
            tenant_id=tenant_id,
        )
        if snapshot is None:
            return context_json

        values = {
            "name": snapshot.name,
            "department": snapshot.department,
            "department_name": snapshot.departmentName or snapshot.department,
            "position": snapshot.position,
            "grade": snapshot.grade,
            "employee_no": snapshot.employeeNo,
            "manager_name": snapshot.managerName,
            "employee_location": snapshot.location,
            "cost_center": snapshot.costCenter,
            "finance_owner_name": snapshot.financeOwnerName,
            "employee_risk_profile": snapshot.riskProfile,
            "role_codes": snapshot.roleCodes,
            "is_admin": snapshot.isAdmin,
        }

        for key, value in values.items():
            if context_json.get(key) in (None, "", [], {}):
                context_json[key] = value

        return context_json

    def _resolve_message(
        self,
        payload: OrchestratorRequest,
    ) -> tuple[str, AgentAssetRead | None]:
        task_asset = None
        if payload.task_id:
            task_asset = self.asset_service.get_asset(payload.task_id)

        if payload.message and payload.message.strip():
            return payload.message.strip(), task_asset

        if task_asset is not None:
            description = str(task_asset.description or "").strip()
            scenario_text = " ".join(str(item) for item in task_asset.scenario_json)
            message = f"{task_asset.name} {description} {scenario_text}".strip()
            return message, task_asset

        if payload.source == AgentRunSource.SCHEDULE.value:
            return "定时风险巡检任务", task_asset

        raise ValueError("message 或 task_id 至少需要提供一个。")

    @staticmethod
    def _select_agent(
        payload: OrchestratorRequest,
        ontology: OntologyParseResult,
    ) -> tuple[str, str]:
        if payload.source == AgentRunSource.SCHEDULE.value:
            return AgentName.HERMES.value, "schedule_source_defaults_to_hermes"
        if payload.source == AgentRunSource.SYSTEM_EVENT.value and ontology.intent == "risk_check":
            return AgentName.HERMES.value, "system_event_risk_check_routes_to_hermes"
        if ontology.intent == "risk_check" and payload.source == AgentRunSource.SCHEDULE.value:
            return AgentName.HERMES.value, "scheduled_risk_check_routes_to_hermes"
        if ontology.intent in {"query", "explain", "draft", "compare", "operate"}:
            return AgentName.USER_AGENT.value, f"{ontology.intent}_routes_to_user_agent"
        return AgentName.USER_AGENT.value, "user_message_defaults_to_user_agent"

    def _select_capabilities(
        self,
        *,
        payload: OrchestratorRequest,
        ontology: OntologyParseResult,
        task_asset: AgentAssetRead | None,
    ) -> dict[str, list[AgentAssetListItem | AgentAssetRead]]:
        if ontology.scenario == "knowledge" and payload.source == AgentRunSource.USER_MESSAGE.value:
            return {
                "rules": [],
                "skills": [],
                "mcps": [],
                "tasks": [],
            }

        domain_value = SCENARIO_TO_DOMAIN.get(ontology.scenario)
        rules = self.execution_engine._rank_assets(
            self.asset_service.list_assets(
                asset_type=AgentAssetType.RULE.value,
                status=AgentAssetStatus.ACTIVE.value,
                domain=domain_value if domain_value not in {"knowledge", "system"} else None,
            ),
            ontology,
        )
        skills = self.execution_engine._rank_assets(
            self.asset_service.list_assets(
                asset_type=AgentAssetType.SKILL.value,
                status=AgentAssetStatus.ACTIVE.value,
                domain=domain_value if domain_value not in {"system"} else None,
            ),
            ontology,
        )
        mcps = self.execution_engine._rank_assets(
            self.asset_service.list_assets(
                asset_type=AgentAssetType.MCP.value,
                status=AgentAssetStatus.ACTIVE.value,
            ),
            ontology,
        )
        tasks: list[AgentAssetListItem | AgentAssetRead] = []
        if task_asset is not None and task_asset.status == AgentAssetStatus.ACTIVE.value:
            tasks.append(task_asset)
        elif payload.source == AgentRunSource.SCHEDULE.value:
            tasks = self.execution_engine._rank_assets(
                self.asset_service.list_assets(
                    asset_type=AgentAssetType.TASK.value,
                    status=AgentAssetStatus.ACTIVE.value,
                ),
                ontology,
            )

        return {
            "rules": rules,
            "skills": skills,
            "mcps": mcps,
            "tasks": tasks,
        }

    @staticmethod
    def _normalize_response_status(status: str) -> str:
        if status == AgentRunStatus.FAILED.value:
            return "failed"
        if status == AgentRunStatus.BLOCKED.value:
            return "blocked"
        return "succeeded"

    @staticmethod
    def _is_expense_application_context(context_json: dict[str, Any]) -> bool:
        context_json = context_json or {}
        context_values = {
            str(context_json.get("session_type") or "").strip(),
            str(context_json.get("entry_source") or "").strip(),
            str(context_json.get("document_type") or "").strip(),
            str(context_json.get("application_stage") or "").strip(),
        }
        conversation_state = context_json.get("conversation_state")
        if isinstance(conversation_state, dict):
            context_values.update(
                {
                    str(conversation_state.get("session_type") or "").strip(),
                    str(conversation_state.get("entry_source") or "").strip(),
                    str(conversation_state.get("document_type") or "").strip(),
                    str(conversation_state.get("application_stage") or "").strip(),
                }
            )
        if context_values & APPLICATION_CONTEXT_VALUES:
            return True

        history = context_json.get("conversation_history")
        if not isinstance(history, list):
            return False
        current_message = re.sub(r"\s+", "", str(context_json.get("user_input_text") or ""))
        looks_like_submit = (
            any(keyword in current_message for keyword in APPLICATION_SUBMIT_KEYWORDS)
            or current_message in APPLICATION_SHORT_CONFIRMATIONS
            or not current_message
        )
        if not looks_like_submit:
            return False
        for item in history[-6:]:
            if not isinstance(item, dict):
                continue
            content = str(item.get("content") or "")
            if "#application-submit" in content or ("费用申请" in content and "确认" in content):
                return True
        return False

    @staticmethod
    def _is_application_submit_result(result: dict[str, Any]) -> bool:
        draft_payload = result.get("draft_payload")
        return (
            isinstance(draft_payload, dict)
            and str(draft_payload.get("draft_type") or "").strip() == "expense_application"
            and str(draft_payload.get("status") or "").strip() == "submitted"
            and bool(
                str(draft_payload.get("claim_no") or draft_payload.get("claim_id") or "").strip()
            )
        )
