# coding=utf-8

"""统一标识构造工具（Core 公共组件）。

约定：
- scoped_id（实体稳定 ID）统一使用 `name_id@belong_to_project_path`。
- executor_id 新格式统一使用 `origin:executor_type:scoped_id`。
- origin 目前支持 `stored` / `inline`。
- 旧格式 `executor_type:scoped_id` 仍兼容解析。
- tool_call_name / action_name（工具调用名称）统一使用 tool 的 scoped_id。

说明：
- 该约定用于跨产品线（云/端/worker）统一审计与展示。
- 若缺少必要字段（name_id/belong_to_project_path），会回退到 `id` 字段，确保不中断运行。
"""

from __future__ import annotations

import uuid
from typing import Any, Dict, Optional

from turbo_agent_core.schema.enums import RunType


INLINE_SPACE_NAME = "inline"
INLINE_PROJECT_NAME_ID = "ephemeral"
EXECUTOR_ORIGIN_STORED = "stored"
EXECUTOR_ORIGIN_INLINE = "inline"

def build_scoped_id(entity: Any) -> str:
    """构造稳定实体 ID：`name_id@space_name/project_name_id[:version]`。

    使用 space_name/project_name_id 组成 project_path，belong_to_project_path（cuid）。
    """

    name_id = getattr(entity, "name_id", None)
    space_name = getattr(entity, "space_name", None)
    project_name_id = getattr(entity, "project_name_id", None)
    # 优先使用 version_id (DB 主键/CUID)，其次使用 version (语义版本)
    version_id = getattr(entity, "version_id", None) or getattr(entity, "version", None)

    if isinstance(name_id, str) and name_id and isinstance(space_name, str) and space_name:
        project_path = f"{space_name}/{project_name_id}" if project_name_id else space_name
        return f"{name_id}@{project_path}:{version_id}" if version_id else f"{name_id}@{project_path}"

    fallback_id = getattr(entity, "id", None)
    if isinstance(fallback_id, str) and fallback_id:
        return fallback_id

    return "unknown"


def build_executor_id(entity: Any, executor_type: Optional[RunType] = None) -> str:
    """构造常驻 executor_id：`stored:executor_type:name_id@space/project:version`。"""

    rt = executor_type or getattr(entity, "run_type", None)
    if isinstance(rt, RunType):
        type_str = rt.value
    else:
        type_str = str(rt) if rt is not None else "Unknown"

    return f"{EXECUTOR_ORIGIN_STORED}:{type_str}:{build_scoped_id(entity)}"


def build_ephemeral_executor_id(entity: Any, executor_type: Optional[RunType] = None) -> str:
    """构造即时 executor_id。

    用途：
    - 适用于内联执行器、预创建会话等尚未持久化实体的临时标识。
    - 优先兼容标准 executor_id 格式；若字段不足，则基于模型、工具等关键信息生成稳定标识。

    返回格式尽量保持为可解析的 `inline:type:name_id@project[:version]`。
    当缺少 project 信息时，统一回退到 `<space_name>/ephemeral`，若 space_name 也缺失才回退到 `inline/ephemeral`。
    """

    entity_id = getattr(entity, "id", None)
    if isinstance(entity_id, str) and entity_id :
        # 若已具备 ID 字段，且 executor_type 可用，则直接构造标准 executor_id 格式，确保兼容性和可解析性。即便存在内联情况，主干依然是该执行体
        return build_executor_id(entity, executor_type)

    rt = executor_type or getattr(entity, "run_type", None)
    if isinstance(rt, RunType):
        type_str = rt.value
    else:
        type_str = str(rt) if rt is not None else "Unknown"

    space_name = getattr(entity, "space_name", None) or INLINE_SPACE_NAME
    project_name_id = getattr(entity, "project_name_id", None) or INLINE_PROJECT_NAME_ID
    belong_to_project_path = getattr(entity, "belong_to_project_path", None) or f"{space_name}/{project_name_id}"

    base_name_id = getattr(entity, "name_id", None) or getattr(entity, "name", None) or "executor"
    normalized_name_id = str(base_name_id).replace(" ", "_")

    model = getattr(entity, "model", None)
    model_name = None
    if model is not None:
        model_name = getattr(model, "name_id", None) or getattr(model, "name", None) or getattr(model, "series_name", None)

    tool_names = []
    for tool in getattr(entity, "tools", []) or []:
        tool_name = getattr(tool, "name_id", None) or getattr(tool, "name", None)
        if tool_name:
            tool_names.append(str(tool_name).replace(" ", "_"))

    detail_parts = []
    if model_name:
        detail_parts.append(f"m_{str(model_name).replace(' ', '_')}")
    if tool_names:
        detail_parts.append(f"t_{'_'.join(tool_names)}")

    enriched_name_id = normalized_name_id
    if detail_parts:
        enriched_name_id = f"{normalized_name_id}__{'__'.join(detail_parts)}"

    version_id = getattr(entity, "version_id", None) or getattr(entity, "version_tag", None) or getattr(entity, "version", None)
    scoped_id = f"{enriched_name_id}@{belong_to_project_path}"
    return f"{EXECUTOR_ORIGIN_INLINE}:{type_str}:{scoped_id}:{version_id}" if version_id else f"{EXECUTOR_ORIGIN_INLINE}:{type_str}:{scoped_id}"


def is_inline_entity(entity: Any) -> bool:
    """判断实体是否为即时内联构造。"""
    return bool(getattr(entity, "is_inline", False))


def build_inline_turbo_entity_data(
    *,
    entity_id: Optional[str] = None,
    name: Optional[str] = None,
    name_id: Optional[str] = None,
    space_name: Optional[str] = None,
    project_name_id: Optional[str] = None,
    belong_to_project_path: Optional[str] = None,
    belong_to_project_id: Optional[str] = None,
    description: Optional[str] = None,
    avatar_uri: Optional[str] = None,
    run_type: Any,
    model: Any = None,
    setting: Any = None,
    tools: Optional[list[Any]] = None,
    extra_data: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    """构造内联 TurboEntity 所需的通用字段。"""

    resolved_id = entity_id or str(uuid.uuid4())

    resolved_space_name = space_name
    resolved_project_name_id = project_name_id
    resolved_project_id = belong_to_project_path or belong_to_project_id

    if resolved_project_id and "/" in resolved_project_id:
        project_space_name, project_name = resolved_project_id.split("/", 1)
        resolved_space_name = resolved_space_name or project_space_name
        resolved_project_name_id = resolved_project_name_id or project_name

    resolved_space_name = resolved_space_name or INLINE_SPACE_NAME
    resolved_project_name_id = resolved_project_name_id or INLINE_PROJECT_NAME_ID
    resolved_project_id = resolved_project_id or f"{resolved_space_name}/{resolved_project_name_id}"

    resolved_name_id = name_id or f"temp_{resolved_id.replace('-', '')[:8]}"
    resolved_name = name or resolved_name_id

    common_data: Dict[str, Any] = {
        "id": resolved_id,
        "name": resolved_name,
        "name_id": resolved_name_id,
        "space_name": resolved_space_name,
        "project_name_id": resolved_project_name_id,
        "belong_to_project_path": resolved_project_id,
        "description": description,
        "avatar_uri": avatar_uri,
        "run_type": run_type,
        "model": model,
        "setting": setting,
        "tools": tools or [],
        "is_inline": True,
    }

    if extra_data:
        common_data.update(extra_data)

    return common_data


def build_tool_call_name(tool: Any) -> str:
    """构造工具调用 name（用于 OpenAI function.name / action.name）。

    约定：tool_call_name = tool 的 `name_id@space_name/project_name_id`。
    """

    return build_scoped_id(tool)

def parse_executor_id(executor_id: str) -> Optional[dict]:
    """解析 executor_id 为组件信息字典。

    支持两种格式：
    - 新格式：`origin:executor_type:scoped_id:version`
    - 旧格式：`executor_type:scoped_id:version`

    例子：
    - "stored:TOOL:my_tool@project_123:1.0"
    - "inline:AGENT:my_agent@demo/project_x"
    - "AGENT:my_agent@project_456"
    """

    try:
        parts = executor_id.split(":")
        if len(parts) < 2:
            return None

        origin = None
        if len(parts) >= 3 and parts[0] in {EXECUTOR_ORIGIN_STORED, EXECUTOR_ORIGIN_INLINE}:
            origin = parts[0]
            executor_type = parts[1]
            scoped_part = ":".join(parts[2:])
        else:
            executor_type = parts[0]
            scoped_part = ":".join(parts[1:])  # 处理可能存在的多个冒号

        if "@" in scoped_part:
            name_id_part, belong_to_part = scoped_part.split("@", 1)
            if ":" in belong_to_part:
                belong_to_project_id, version = belong_to_part.split(":", 1)
            else:
                belong_to_project_id = belong_to_part
                version = None
        else:
            name_id_part = scoped_part
            belong_to_project_id = None
            version = None

        return {
            "origin": origin,
            "is_inline": origin == EXECUTOR_ORIGIN_INLINE,
            "type": executor_type,
            "name_id": name_id_part,
            "project_path": belong_to_project_id,
            "version": version
        }
    except Exception:
        return None

def parse_run_type(executor_type_str: str) -> Optional[RunType]:
    """将 executor_type 字符串解析为 RunType 枚举。"""

    try:
        return RunType(executor_type_str)
    except ValueError:
        return None

def is_tool_executor(executor_type: RunType) -> bool:
    """判断 executor_type 字符串是否表示工具执行者。"""
    is_tool = False
    executor_type_str = str(executor_type)
    # 判断是否为 Tool 类型
    # RunType: Tool, LLMTool, AgentTool, MCP, CodeScript, BUILTIN, Frontend, API -> ToolCallRecord
    # RunType: LLM, AGENT, Character -> Message
    if "Tool" in executor_type_str:  # Covers Tool, LLMTool, AgentTool
        is_tool = True
    elif executor_type_str in ["MCP", "CodeScript", "BUILTIN", "Frontend", "API"]:
        is_tool = True

    return is_tool
