from __future__ import annotations

import uuid
from datetime import datetime, timezone
from typing import AsyncIterator, Iterator, Optional, List, Union
from loguru import logger
from pydantic import Field

from turbo_agent_core.schema.events import (
    BaseEvent,
    ExecutorMetadata,
    RunLifecycleCreatedEvent,
    RunLifecycleCreatedPayload,
    RunLifecycleFailedEvent,
    RunLifecycleFailedPayload,
    UserInfo,
)
from turbo_agent_core.schema.agents import Character, APITool, LLMTool, AgentTool, BuiltinTool, Tool
from turbo_agent_core.schema.states import Conversation, Message, MessageRole

from turbo_agent_runtime.utils.executor_identity import build_executor_id
from .agent import AgentRuntime


class CharacterRuntime(Character):
    tools: List[Union[APITool, LLMTool, AgentTool, BuiltinTool, Tool]] = Field(default_factory=list)

    def _build_agent_runtime(self) -> AgentRuntime:
        """构造内部 AgentRuntime，统一传递所有必需字段。"""
        return AgentRuntime(
            id=self.id,
            name=self.name,
            name_id=self.name_id,
            space_name=self.space_name,
            project_name_id=self.project_name_id,
            belong_to_project_path=self.belong_to_project_path,
            model=self.model,
            modelParameter=self.modelParameter,
            setting=self.setting,
            expose_inner_thought=getattr(self, "expose_inner_thought", True),
            tools=self.tools or [],
        )

    def _build_executor_metadata(self) -> ExecutorMetadata:
        """构造 Character 粒度的 ExecutorMetadata。"""
        return ExecutorMetadata(
            id=self.id,
            name=self.name,
            belong_to_project_path=self.belong_to_project_path,
            name_id=self.name_id,
            description=self.description,
            avatar_uri=self.avatar_uri,
            run_type=self.run_type,
            version_id=self.version_id,
            version=self.version_tag,
        )

    def _emit_error_events(
        self,
        error: Exception,
        *,
        user_id: str = "unknown",
        username: str = "unknown",
    ) -> Iterator[BaseEvent]:
        """当内部构造失败时，发出符合协议的 created + failed 事件流，避免消费方卡死。"""
        trace_id = str(uuid.uuid4())
        run_id = str(uuid.uuid4())
        executor_id = build_executor_id(self, self.run_type)
        ts_ms = datetime.now(timezone.utc).timestamp() * 1000

        yield RunLifecycleCreatedEvent(
            trace_id=trace_id,
            run_id=run_id,
            run_path=[run_id],
            executor_id=executor_id,
            executor_type=self.run_type,
            executor_path=[executor_id],
            executor_metadata=self._build_executor_metadata(),
            user_metadata=UserInfo(id=str(user_id), username=str(username)),
            timestamp=ts_ms,
            payload=RunLifecycleCreatedPayload(input_data=None),
        )
        yield RunLifecycleFailedEvent(
            trace_id=trace_id,
            run_id=run_id,
            run_path=[run_id],
            executor_id=executor_id,
            executor_type=self.run_type,
            executor_path=[executor_id],
            timestamp=ts_ms + 1,
            payload=RunLifecycleFailedPayload(
                error={"code": type(error).__name__, "message": str(error)},
            ),
        )

    async def _a_emit_error_events(
        self,
        error: Exception,
        **kwargs,
    ) -> AsyncIterator[BaseEvent]:
        """异步版错误事件发射。"""
        user_id = kwargs.get("user_id") or kwargs.get("userId") or "unknown"
        username = kwargs.get("username") or "unknown"
        for event in self._emit_error_events(error, user_id=user_id, username=username):
            yield event

    def run(self, input: Conversation, **kwargs) -> Message:
        """
        Character 运行时：构造 Agent -> 代理执行。
        要求：仅接受 Conversation；
        """
        agent = self._build_agent_runtime()
        return agent.run(input, **kwargs)

    def stream(self, input: Conversation, **kwargs) -> Iterator[BaseEvent]:
        """
        同步流式：仅接受 Conversation；事件直接透传。
        """
        try:
            agent = self._build_agent_runtime()
        except Exception as e:
            logger.error(f"CharacterRuntime 构造 AgentRuntime 失败: {e}")
            yield from self._emit_error_events(e, user_id=kwargs.get("user_id", "unknown"), username=kwargs.get("username", "unknown"))
            return
        
        inner_executor_id = build_executor_id(agent, agent.run_type)
        outer_executor_id = build_executor_id(self, self.run_type)

        # 直接透传底层 Agent 的事件
        for event in agent.stream(input, **kwargs):
            # Patch identity to ensure consistency
            if event.executor_id == inner_executor_id:
                event.executor_id = outer_executor_id
                event.executor_type = self.run_type
            
            if event.executor_path:
                event.executor_path = [
                    outer_executor_id if x == inner_executor_id else x 
                    for x in event.executor_path
                ]

            # Character 只是 Agent 的一层壳，但为了保持 Character 的身份，
            # 我们需要拦截 run.lifecycle created 事件，并替换 executor_metadata
            if event.type == "run.lifecycle.created":
                if event.executor_metadata:
                    # 覆盖为 Character 的元数据
                    event.executor_metadata.id = self.id
                    event.executor_metadata.name = self.name
                    event.executor_metadata.name_id = self.name_id
                    event.executor_metadata.description = self.description
                    event.executor_metadata.avatar_uri = self.avatar_uri
                    event.executor_metadata.run_type = self.run_type
                    event.executor_metadata.version_id = self.version_id
                    event.executor_metadata.version = self.version_tag
                
                # 同时也修正 executor_type
                event.executor_type = self.run_type
            
            yield event

    async def a_run(self, input: Conversation, **kwargs) -> Message:
        agent = self._build_agent_runtime()
        return await agent.a_run(input, **kwargs)

    async def a_stream(self, input: Conversation, **kwargs) -> AsyncIterator[BaseEvent]:
        """
        异步流式：仅接受 Conversation；事件直接透传。
        """
        try:
            agent = self._build_agent_runtime()
        except Exception as e:
            logger.error(f"CharacterRuntime 构造 AgentRuntime 失败: {e}")
            async for event in self._a_emit_error_events(e, **kwargs):
                yield event
            return
        
        inner_executor_id = build_executor_id(agent, agent.run_type)
        outer_executor_id = build_executor_id(self, self.run_type)

        async for event in agent.a_stream(input, **kwargs):
            # Patch identity to ensure consistency
            if event.executor_id == inner_executor_id:
                event.executor_id = outer_executor_id
                event.executor_type = self.run_type
            
            if event.executor_path:
                event.executor_path = [
                    outer_executor_id if x == inner_executor_id else x 
                    for x in event.executor_path
                ]

            # Character 只是 Agent 的一层壳，但为了保持 Character 的身份，
            # 我们需要拦截 run.lifecycle created 事件，并替换 executor_metadata
            if event.type == "run.lifecycle.created":
                if event.executor_metadata:
                    # 覆盖为 Character 的元数据
                    event.executor_metadata.id = self.id
                    event.executor_metadata.name = self.name
                    event.executor_metadata.name_id = self.name_id
                    event.executor_metadata.description = self.description
                    event.executor_metadata.avatar_uri = self.avatar_uri
                    event.executor_metadata.run_type = self.run_type
                    event.executor_metadata.version_id = self.version_id
                    event.executor_metadata.version = self.version_tag
                
                # 同时也修正 executor_type
                event.executor_type = self.run_type
            
            yield event
