from __future__ import annotations

from typing import Any, Optional

from .core.llm_middleware import LLMMiddleware, MiddlewareConfig, create_middleware
from .discovery.auto_discover import protect as _discovery_protect
from .discovery.auto_discover import unprotect


def wrap(
    client: Any, *, provider: Optional[str] = None, middleware: Optional[LLMMiddleware] = None
) -> Any:
    """
    Stable wrapper entrypoint.

    This wraps a provider client in-place (monkey patches request methods) so Entropic can:
    - inject stability/grounding instructions
    - adjust temperature / retries (if enabled)
    - record evidence in middleware call history

    Supported (best-effort):
    - OpenAI-compatible clients (OpenAI, OpenRouter) via `.chat.completions.create`
    - Anthropic clients via `.messages.create`
    """
    from .core.llm_middleware import wrap_anthropic, wrap_openai, wrap_openrouter

    if middleware is None:
        middleware = create_middleware()

    prov = (provider or "").lower().strip() if provider else ""

    if prov in {"openai", "openrouter"}:
        if prov == "openrouter":
            return wrap_openrouter(client, middleware=middleware)
        return wrap_openai(client, middleware=middleware)
    if prov in {"anthropic", "claude"}:
        return wrap_anthropic(client, middleware=middleware)

    # Auto-detect.
    if hasattr(client, "chat") and getattr(getattr(client, "chat", None), "completions", None):
        return wrap_openai(client, middleware=middleware)
    if hasattr(client, "messages"):
        return wrap_anthropic(client, middleware=middleware)

    raise TypeError(
        "Unsupported client shape for entropic_core.wrap(). "
        "Pass provider='openai'/'anthropic' or provide a compatible client."
    )


def protect(
    brain: Any = None,
    target: Any = None,
    *,
    # Runtime (drop-in) mode:
    mode: Optional[str] = None,
    client: Any = None,
    provider: str = "",
    model: str = "",
    run_dir: str = "entropic_runs",
    config_path: Optional[str] = None,
    overrides: Optional[dict] = None,
    print_effective_config: bool = False,
    auto_report: bool = True,
    atexit_report: bool = True,
) -> Any:
    """
    Stable entrypoint.

    Two supported patterns:
    1) Zero-config import-hook protection (legacy): protect(brain=None, target=None)
    2) Runtime drop-in reliability session (recommended): protect(mode="balanced", client=..., provider="openrouter")

    Runtime mode is enabled when `mode` is provided (or `config_path`/`overrides`/`run_dir` are set).
    """
    wants_runtime = (
        mode is not None
        or client is not None
        or config_path is not None
        or overrides is not None
        or (run_dir and run_dir != "entropic_runs")
        or provider
        or model
    )
    if not wants_runtime:
        return _discovery_protect(brain=brain, target=target)

    from .core.runtime_session import start_runtime_session, start_runtime_session_atexit

    starter = start_runtime_session_atexit if atexit_report else start_runtime_session
    sess = starter(
        mode=mode,
        run_dir=run_dir,
        provider=provider,
        model=model,
        config_path=config_path,
        overrides=overrides,
        auto_report=auto_report,
    )
    if print_effective_config:
        import json

        print(json.dumps(sess.effective_config, indent=2))

    if client is not None:
        return sess.wrap(client, provider=provider or None)
    return sess


__all__ = ["protect", "unprotect", "create_middleware", "wrap", "LLMMiddleware", "MiddlewareConfig"]
