from typing import Any

from app.agent.runtime_loader import (
    activate_agent_service,
    begin_agent_shutdown,
    close_materialized_terminal_sessions,
    get_agent_manager as get_runtime_agent_manager,
    get_running_agent_manager as get_runtime_running_agent_manager,
    is_tool_factory_materialized,
    reconcile_agent_service,
)
from app.agent.llm.gateway import register_llm_provider_runtime
from app.application.agent import register_agent_service_providers
from app.application.messaging.skill import register_skill_catalog_provider
from app.runtime.settings import RuntimeSettingsCompat

settings = RuntimeSettingsCompat()
from app.runtime.events import Event, eventmanager
from app.runtime.log import logger
from app.schemas.types import EventType


AGENT_BLOCKING_EXECUTOR_SHUTDOWN_TIMEOUT_SECONDS = 10.0


def _get_skill_catalog() -> Any:
    """按需返回 Agent 技能目录实现，供消息应用层消费端口。"""
    from app.agent.skills.registry import SkillHelper

    return SkillHelper()


def _get_llm_provider_runtime() -> Any:
    """按需返回 LLM provider 运行时，实现只在真实调用边界加载。"""
    from app.agent.llm.provider import LLMProviderManager

    return LLMProviderManager()


# 嵌入式启动器可显式注入 manager；常规进程使用 Capability Runtime。
agent_manager: Any = None


def _event_changed_keys(event: Event | None) -> set[str]:
    """兼容对象和 dict 两种配置事件载荷。"""
    if event is None:
        return set()
    event_data = event.event_data
    if isinstance(event_data, dict):
        keys = event_data.get("key", set())
    else:
        keys = getattr(event_data, "key", set())
    if isinstance(keys, str):
        return {keys}
    return {str(key) for key in (keys or set())}


def _get_agent_manager() -> Any:
    """兼容显式注入对象，否则按需解析 canonical manager。"""
    return agent_manager if agent_manager is not None else get_runtime_agent_manager()


def _get_running_agent_manager() -> Any | None:
    """只返回已运行实例，状态探测不得触发 Agent 物化。"""
    if agent_initializer._compat_injected:
        return agent_initializer._manager
    return get_runtime_running_agent_manager()


def _get_prompt_manager() -> Any:
    """首个提示词调用才导入模板管理器。"""
    from app.agent.prompt import prompt_manager

    return prompt_manager


def _get_capability_manager() -> Any:
    """首个多模态调用才导入 Agent 能力管理器。"""
    from app.agent.llm.capability import AgentCapabilityManager

    return AgentCapabilityManager


def _get_llm_helper() -> Any:
    """首个模型能力查询才导入 LLM helper。"""
    from app.agent.llm.helper import LLMHelper

    return LLMHelper


def _get_manual_redo_prompt_builder() -> Any:
    """首个整理接管请求才导入对应提示词构建器。"""
    from app.agent.prompt.transfer_redo import build_manual_redo_prompt

    return build_manual_redo_prompt


async def _handle_agent_config_changed(event: Event) -> None:
    """把配置事件交给当前全局 initializer，避免监听器持有过期实例。"""
    await agent_initializer.handle_config_changed(event)


class AgentInitializer:
    """
    AI智能体初始化器
    """

    def __init__(self):
        self._initialized = False
        self._manager: Any = None
        self._compat_injected = False
        self._shutdown_started = False
        self._shutdown_complete = False
        eventmanager.add_event_listener(
            EventType.ConfigChanged,
            _handle_agent_config_changed,
        )

    async def initialize(self) -> bool:
        """
        初始化AI智能体管理器
        """
        try:
            self._shutdown_started = False
            self._shutdown_complete = False
            if agent_manager is not None:
                if not settings.AI_AGENT_ENABLE:
                    logger.info("AI智能体功能未启用")
                    return True
                self._manager = agent_manager
                self._compat_injected = True
                await agent_manager.initialize()
            else:
                self._manager = await activate_agent_service()
                self._compat_injected = False
                if self._manager is None:
                    logger.info("AI智能体功能未启用")
                    return True
            self._initialized = True
            logger.info("AI智能体管理器初始化成功")
            return True

        except Exception as e:
            logger.error(f"AI智能体管理器初始化失败: {e}")
            return False

    async def handle_config_changed(self, event: Event) -> None:
        """仅在 manifest watch 命中时协调 service，关闭态保持 fail closed。"""
        changed_keys = _event_changed_keys(event)
        if (
            not changed_keys
            or self._compat_injected
            or self._shutdown_started
            or self._shutdown_complete
        ):
            return
        try:
            self._manager = await reconcile_agent_service(
                reason="agent_service_config_changed",
                changed_keys=changed_keys,
                retry=True,
            )
            self._initialized = self._manager is not None
        except Exception as error:
            self._manager = None
            self._initialized = False
            logger.debug(f"配置变更协调AI智能体失败: {error}")

    async def cleanup(self) -> bool:
        """清理 initializer 引用；未收敛的显式注入对象继续由本实例持有。"""
        try:
            manager = self._manager
            compat_injected = self._compat_injected
            if manager is None:
                return True
            if compat_injected and await manager.close() is False:
                logger.error("AI智能体管理器仍有会话 owner 未收敛")
                return False
            logger.info("AI智能体管理器已关闭")
            self._initialized = False
            self._manager = None
            self._compat_injected = False
            return True

        except Exception as e:
            logger.debug(f"关闭AI智能体管理器时发生错误: {e}")
            return False


# 全局AI智能体初始化器实例
agent_initializer = AgentInitializer()

# application 门面仅保存 provider；下列注册不会导入 Agent 实现。
register_agent_service_providers(
    agent_manager_provider=_get_agent_manager,
    running_agent_manager_provider=_get_running_agent_manager,
    prompt_manager_provider=_get_prompt_manager,
    capability_manager_provider=_get_capability_manager,
    llm_helper_provider=_get_llm_helper,
    manual_redo_prompt_builder_provider=_get_manual_redo_prompt_builder,
)
register_skill_catalog_provider(_get_skill_catalog)
register_llm_provider_runtime(_get_llm_provider_runtime)


async def init_agent() -> bool:
    """
    在应用事件循环中初始化AI智能体。
    """
    try:
        return await agent_initializer.initialize()

    except Exception as e:
        logger.error(f"初始化AI智能体时发生错误: {e}")
        return False


async def stop_agent() -> bool:
    """
    停止AI智能体，并在全部会话和工具资源释放后返回 True。
    """
    converged = True
    close_blocking_executors = None
    agent_initializer._shutdown_started = True
    try:
        if is_tool_factory_materialized():
            from app.agent.tools.base import (
                begin_blocking_executor_shutdown,
                close_blocking_executors as close_executors,
            )

            # 必须在任何 manager await 之前封口，避免旧会话趁收尾窗口提交新同步调用。
            begin_blocking_executor_shutdown(cancel_futures=True)
            close_blocking_executors = close_executors
    except Exception as e:
        logger.error(f"封住AI智能体阻塞工具提交时发生错误: {e}")
        converged = False

    try:
        if not agent_initializer._shutdown_complete:
            if agent_initializer._compat_injected:
                service_converged = await agent_initializer.cleanup()
            else:
                service_converged = await begin_agent_shutdown()
                if service_converged is not False:
                    service_converged = await agent_initializer.cleanup()
            converged = converged and service_converged is not False
    except Exception as e:
        logger.error(f"停止AI智能体时发生错误: {e}")
        converged = False

    if close_blocking_executors is not None:
        try:
            blocking_converged = await close_blocking_executors(
                timeout_seconds=AGENT_BLOCKING_EXECUTOR_SHUTDOWN_TIMEOUT_SECONDS,
                cancel_futures=True,
            )
            converged = converged and blocking_converged
        except Exception as e:
            logger.error(f"关闭AI智能体阻塞工具线程池时发生错误: {e}")
            converged = False

    if converged:
        try:
            await close_materialized_terminal_sessions()
        except Exception as e:
            logger.error(f"关闭AI智能体终端会话时发生错误: {e}")
            converged = False
    agent_initializer._shutdown_complete = converged
    return converged
