#  coding=utf-8
#  本文档定义了 基础数据模型，以支持 智能体（Agent）、角色（Character）和工具（Tool）构建过程中所使用到的基础类型
from __future__ import annotations

from enum import Enum
from typing import List, Optional, Dict,Any, TYPE_CHECKING
from abc import ABC, abstractmethod

from pydantic import BaseModel, Field, ValidationError
from turbo_agent_core.schema.enums import JSON, ModelApiProvider, SourceType, WebProtocol,RunType, BasicType, ParameterPosition, SpaceType

if TYPE_CHECKING:
    from turbo_agent_core.schema.events import BaseEvent

class ModelParameters(BaseModel):
    temperature: Optional[float] = Field(default=0.7, ge=0.0, le=2.0, description="采样温度，值越高输出越发散，值越低输出越稳定。")
    top_p: Optional[float] = Field(default=1.0, ge=0.0, le=1.0, description="核采样阈值，限制模型从累计概率前 top_p 的候选词中采样。")
    max_tokens: Optional[int] = Field(default=None, ge=1, description="本次生成允许输出的最大 token 数。")
    stop: Optional[List[str]] = Field(default=None, description="停止词列表；当输出命中任一停止词时提前结束生成。")
    presence_penalty: Optional[float] = Field(default=0.0, ge=-2.0, le=2.0, description="存在惩罚，提升模型引入新话题的倾向。")
    frequency_penalty: Optional[float] = Field(default=0.0, ge=-2.0, le=2.0, description="频率惩罚，降低重复生成相同内容的倾向。")
    logit_bias: Optional[Dict[str, float]] = Field(default=None, description="对指定 token 的 logits 做偏置调整，键通常为 token 标识，值为偏置分数。")
    user: Optional[str] = Field(default=None, description="透传给模型服务的调用用户标识，用于审计或限流。")
    extra: Optional[JSON] = Field(default=None, description="附加模型参数，会原样透传给底层模型调用。")

#  大模型实例信息,每个用户可能通过自己搭建、购买同一个模型的不同实例，在实际使用时，根据用户的权限、场景等信息，选择合适的实例进行调用
class ModelInstance(BaseModel):
    id: str = Field(description="模型实例 ID。")
    label: str = Field(description="模型实例显示名称（可以为中文）。")
    space_name: str = Field(description="模型实例所属空间英文名。")
    series_name: str = Field(description="模型所属系列英文名。")
    model_name: str = Field(description="模型英文名称。")
    version: Optional[str] = Field(default=None, description="模型实例版本号。")
    project_name_id: Optional[str] = Field(default=None, description="模型实例所属项目英文名。")
    description: str = Field(description="模型实例描述。")
    request_model_id: str = Field(description="实际发起模型请求时使用的模型 ID。")
    is_active: bool = Field(description="模型实例当前是否启用。")
    provider: ModelApiProvider = Field(default=ModelApiProvider.openai, description="模型服务提供商。")
    endpoint: Optional[Endpoint] = Field(default=None, description="模型实例对应的访问端点配置。")
    local_launch_spec: Optional["LocalLaunchSpec"] = Field(default=None, description="本地启动配置，描述如何在本地拉起该模型。")
    token_cost_input: Optional[float] = Field(default=None, description="输入 token 单价。")
    token_cost_output: Optional[float] = Field(default=None, description="输出 token 单价。")
    concurrent_limit: Optional[int] = Field(default=None, description="并发调用上限。")
    rpm_limit: Optional[int] = Field(default=None, description="每分钟请求数限制。")
    tpm_limit: Optional[int] = Field(default=None, description="每分钟 token 数限制。")
    request_params: Optional[JSON] = Field(default=None, description="预设附加请求参数，会在调用时透传。")


class LocalLaunchMode(str, Enum):
    """本地模型启动方式的描述（仅用于配置表达，不包含具体实现）。"""
    external = "external"   # 不由本地启动，仅使用既有 endpoint
    ollama = "ollama"       # 本地 Ollama 管理（通常仍通过 endpoint 访问）
    vllm = "vllm"           # 本地 vLLM 服务（通常通过 endpoint 访问）
    llamacpp = "llamacpp"   # llama.cpp 本地进程/服务


class LocalLaunchSpec(BaseModel):
    """本地启动描述：用于 local 模块拉起/探活/停止本地模型。

    说明：
    - core 只定义“如何描述启动”，不定义“如何启动”的实现。
    - local 模块可根据 provider/endpoint.source_type/mode 选择不同适配器（vLLM、Ollama、llama.cpp 等）。
    """

    # pydantic 会把 model_ 作为受保护的命名空间；这里显式关闭，避免 model_path/served_model_name 警告。
    model_config = {"protected_namespaces": ()}

    mode: LocalLaunchMode = Field(default=LocalLaunchMode.external, description="本地模型启动模式。")
    command: Optional[str] = Field(default=None, description="启动本地模型时使用的命令。")
    args: List[str] = Field(default_factory=list, description="启动命令参数列表。")
    env: Dict[str, str] = Field(default_factory=dict, description="启动进程时注入的环境变量。")
    workdir: Optional[str] = Field(default=None, description="启动命令执行目录。")

    host: Optional[str] = Field(default=None, description="本地服务监听地址。")
    port: Optional[int] = Field(default=None, description="本地服务监听端口。")

    model_path: Optional[str] = Field(default=None, description="本地模型文件路径。")
    served_model_name: Optional[str] = Field(default=None, description="对外提供服务时暴露的模型名称。")

    healthcheck_url: Optional[str] = Field(default=None, description="服务健康检查地址。")
    startup_timeout_ms: int = Field(default=60_000, description="启动超时时间，单位毫秒。")

    extra: Optional[JSON] = Field(default=None, description="扩展启动参数。")

# 版本管理基础信息
class VersionInfo(BaseModel):
    version: str = Field(default="0.0.1", description="版本号。")
    update_info: str = Field(default="initial", description="本次版本更新说明。")
    version_hash: str = Field(description="当前版本内容哈希，用于比对版本差异。")

class Endpoint(BaseModel):
    id: str = Field(description="端点 ID。")
    name: Optional[str] = Field(default=None, description="端点显示名称。")
    protocol: WebProtocol = Field(default=WebProtocol.HTTP, description="端点访问协议。")
    source_type: SourceType = Field(default=SourceType.External, description="端点来源类型，例如外部服务或本地服务。")
    url: Optional[str] = Field(default=None, description="完整访问地址。")
    baseURL: Optional[str] = Field(default=None, description="基础 URL，适合按路径拼接调用。")
    accessKey: Optional[str] = Field(default=None, description="端点访问密钥，仅适用于直接配置密钥的场景。")

# TurboAgent项目下的基础实体类型，原则上，如果定义为TurboEntity，并且run_type类型非NONE说明该实体可以直接运行
class TurboEntity(BaseModel, ABC):
    id: str = Field(description="实体 ID。")
    name: str = Field(description="实体显示名称。")
    space_name: str = Field(description="所属空间英文标识。")
    project_name_id: Optional[str]=Field(default=None, description="所属项目英文标识。")
    belong_to_project_path: Optional[str]=Field(default=None, description="所属项目路径，格式为 space/project。")
    name_id: str = Field(description="实体英文标识，用于程序侧唯一识别。")
    description: Optional[str] = Field(default=None, description="实体描述。")
    avatar_uri: Optional[str] = Field(default=None, description="实体头像或图标地址。")
    is_inline: bool = Field(default=False, description="是否为运行期内联构造的临时实体。")
    run_type: RunType = Field(default=RunType.NoneType, description="实体运行类型，决定其输入输出契约。")
    created_at: Optional[int] = Field(default=None, description="创建时间戳。")
    updated_at: Optional[int] = Field(default=None, description="最近更新时间戳。")
    # 此处定义一个待实现方法，用于当前实体完成任务
    @abstractmethod
    def run(self, **kwargs):
        raise NotImplementedError()
    @abstractmethod
    def stream(self, **kwargs):
        raise NotImplementedError()
    @abstractmethod
    async def a_run(self, **kwargs):
        raise NotImplementedError()
    # 此处定义一个待实现方法，用于当前实体完成任务，返回流式结果，当前方法输入输出可以调整。
    @abstractmethod
    async def a_stream(self, **kwargs):
        raise NotImplementedError()

    def should_expose_inner_thought(self) -> bool:
        return bool(getattr(self, "expose_inner_thought", True))

    def filter_event_for_inner_thought(self, event: "BaseEvent") -> Optional["BaseEvent"]:
        if self.should_expose_inner_thought():
            return event

        if event.type.startswith("content.reasoning"):
            return None

        if event.type == "content.agent.result.delta" and getattr(event.payload, "part", None) == "reasoning":
            return None

        if event.type == "content.action.result.delta" and getattr(event.payload, "part", None) == "reasoning":
            return None

        if event.type == "content.agent.result.end" and hasattr(event.payload, "full_reasoning"):
            event.payload.full_reasoning = None

        return event


class BriefTurboEntity(BaseModel):
    id: str = Field(description="实体 ID。")
    name: str = Field(description="实体显示名称。")
    name_id: str = Field(description="实体英文标识。")
    belong_to_project_path: Optional[str] = Field(default=None, description="所属项目路径，格式为 space/project。")
    space: str = Field(description="所属空间英文名。")
    project_name_id: str = Field(description="所属项目英文名。")
    description: Optional[str] = Field(default=None, description="实体摘要描述。")
    avatar_url: Optional[str] = Field(default=None, description="实体头像访问地址。")
    version_tag: Optional[str] = Field(default=None, description="默认或当前版本标签。")


class DetailTurboEntity(BaseModel):
    id: str = Field(description="实体 ID。")
    name: str = Field(description="实体显示名称。")
    name_id: str = Field(description="实体英文标识。")
    space: str = Field(default=None, description="所属空间英文名。")
    belong_to_project_path: Optional[str] = Field(default=None, description="所属项目路径，格式为 space/project。")
    version_tag: Optional[str] = Field(default=None, description="当前详情对应的版本标签。")
    description: Optional[str] = Field(default=None, description="实体详细描述。")
    avatar_url: Optional[str] = Field(default=None, description="实体头像访问地址。")


class Parameter(BaseModel):
    id: Optional[str] = Field(default=None, description="参数 ID。")
    idx: int = Field(default=0, description="参数顺序索引。")
    required: bool = Field(default=False, description="该参数是否必填。")
    name: str = Field(description="参数名称。")
    description: str = Field(default="", description="参数含义说明。")
    default: Optional[Any] = Field(default=None, description="参数默认值。")
    enum_values: Optional[List[str]] = Field(default=None, description="当参数为枚举类型时的可选值列表。")
    position: Optional[ParameterPosition] = Field(default=None, description="参数所在位置，例如 body、query。")
    type: BasicType = Field(description="参数基础类型。")
    type_ref: Optional[BasicType] = Field(default=None, description="当参数为数组时，表示数组元素类型。")
    parameters: Optional[List[Parameter]] = Field(default=None, description="当参数为对象或对象数组时，其内部字段定义。")
    json_schema: Optional[dict] = Field(default=None, description="参数对应的原始 JSON Schema 片段。")

    class Config:
        arbitrary_types_allowed = True

# ==================== 保留字列表 ====================
# 这些路径不能被用作 spaceName
RESERVED_NAMES = {
    "api", "auth", "admin", "static", "assets", 
    "login", "logout", "register", "signup",
    "settings", "profile", "dashboard", "search",
    "new", "create", "edit", "delete", "import", 
    "projects","project","workshop","forge","lab","laboratory",
    "export","chat","job","task","jobs","tasks",
    "workset","workspace","agent","character","tool",
    "worksets","workspaces","agents","characters","tools",
    "forums","turbobook","agbook","characterbook","agentbook",
    "new","true","false","model","space","organization","member",
    "spark","backend","knowledge","pay","config","factory","class",
    "object","robot","embodied","friends","work","employ","employee",
    "official","support","help","docs","documentation","doc","api-docs","apidocs",
    "self","me","administrator","root","system","sys","internal","society",
    "community","public","private","default","common","shared",
}

class Space(BaseModel):
    space_name:str = Field(description="空间英文名。")
    type:SpaceType = Field(description="空间类型。")

class ModelSeries(BaseModel):
    space_name: str = Field(description="所属空间英文名。")
    formal_name: str = Field(description="模型系列正式名称，供展示使用。")
    series_name: str = Field(description="模型系列英文名，通常作为模型 ID 的组成部分。")
    description: Optional[str] = Field(default=None, description="模型系列描述。")
    

class Project(BaseModel):
    space_name: str = Field(description="所属空间英文名。")
    project_name: str = Field(description="项目显示名称。")
    project_name_id: str = Field(description="项目英文标识。")