"""Agent 编排服务门面。

chain 层需要触发 Agent 后台任务、渲染提示词、查询模型能力时统一经本模块调用。
具体实现由 startup 组合根注册，形成依赖倒置：

    chain -> application.agent <- startup -> agent

门面保存 provider 而非重量级实现对象，注册本身不会物化 Agent、LLM 或工具树。
本模块禁止静态或函数内导入 app.agent，否则会重新形成跨层循环依赖。
"""

from typing import Any, Callable, Optional

Provider = Callable[[], Any]

# provider 注册表由 startup/initializers/agent.py 在组合根装配。
_agent_manager_provider: Optional[Provider] = None
_running_agent_manager_provider: Optional[Provider] = None
_prompt_manager_provider: Optional[Provider] = None
_agent_capability_manager_provider: Optional[Provider] = None
_llm_helper_provider: Optional[Provider] = None
_manual_redo_prompt_builder_provider: Optional[Provider] = None


def register_agent_service_providers(
        *,
        agent_manager_provider: Provider,
        running_agent_manager_provider: Provider,
        prompt_manager_provider: Provider,
        capability_manager_provider: Provider,
        llm_helper_provider: Provider,
        manual_redo_prompt_builder_provider: Provider,
) -> None:
    """注册 Agent 服务 provider，保持组合根装配阶段零重量实现导入。"""
    global _agent_manager_provider, _running_agent_manager_provider
    global _prompt_manager_provider, _agent_capability_manager_provider
    global _llm_helper_provider, _manual_redo_prompt_builder_provider
    _agent_manager_provider = agent_manager_provider
    _running_agent_manager_provider = running_agent_manager_provider
    _prompt_manager_provider = prompt_manager_provider
    _agent_capability_manager_provider = capability_manager_provider
    _llm_helper_provider = llm_helper_provider
    _manual_redo_prompt_builder_provider = manual_redo_prompt_builder_provider


def register_agent_services(
        agent_manager: Any,
        prompt_manager: Any,
        capability_manager: Any,
        llm_helper: Any,
        manual_redo_prompt_builder: Optional[Callable[[Any], str]] = None,
) -> None:
    """兼容直接对象注入；生产组合根应注册惰性 provider。"""
    register_agent_service_providers(
        agent_manager_provider=lambda: agent_manager,
        running_agent_manager_provider=lambda: agent_manager,
        prompt_manager_provider=lambda: prompt_manager,
        capability_manager_provider=lambda: capability_manager,
        llm_helper_provider=lambda: llm_helper,
        manual_redo_prompt_builder_provider=lambda: manual_redo_prompt_builder,
    )


def _resolve(provider: Optional[Provider], service_name: str) -> Any:
    """解析已注册服务；缺少组合根装配时给出稳定错误。"""
    if provider is None:
        raise RuntimeError(
            f"Agent 服务 {service_name} 未注册："
            "请先导入 app.startup.initializers.agent 完成组合根装配"
        )
    return provider()


def get_agent_manager() -> Any:
    """返回 canonical AgentManager；调用可能触发实现物化。"""
    return _resolve(_agent_manager_provider, "agent_manager")


def get_running_agent_manager() -> Any | None:
    """返回已进入 RUNNING 的 AgentManager，不触发实现物化。"""
    return _resolve(_running_agent_manager_provider, "running_agent_manager")


def get_prompt_manager() -> Any:
    """按需返回提示词管理器。"""
    return _resolve(_prompt_manager_provider, "prompt_manager")


def supports_image_input(
        provider: Optional[str] = None,
        model: Optional[str] = None,
        base_url: Optional[str] = None,
        base_url_preset: Optional[str] = None,
) -> bool:
    """判断当前模型是否启用了图片输入能力。"""
    llm_helper = _resolve(_llm_helper_provider, "llm_helper")
    return llm_helper.supports_image_input(
        provider=provider,
        model=model,
        base_url=base_url,
        base_url_preset=base_url_preset,
    )


def is_audio_input_available() -> bool:
    """判断语音输入能力是否可用。"""
    capability_manager = _resolve(
        _agent_capability_manager_provider,
        "agent_capability_manager",
    )
    return capability_manager.is_audio_input_available()


def transcribe_audio(content: bytes, filename: str = "input.ogg") -> Optional[str]:
    """把音频内容转写为文本。"""
    capability_manager = _resolve(
        _agent_capability_manager_provider,
        "agent_capability_manager",
    )
    return capability_manager.transcribe_audio(content, filename=filename)


def build_manual_redo_prompt(history: Any) -> str:
    """构造整理记录 AI 重新整理提示词（builder 由 agent 层注册）。"""
    builder = _resolve(
        _manual_redo_prompt_builder_provider,
        "manual_redo_prompt_builder",
    )
    if builder is None:
        raise RuntimeError("整理记录重新整理提示词构建器未注册")
    return builder(history)
