"""Helper script for langgraph_platform_integration.robot tests.

Each subcommand is a self-contained check that prints a sentinel on success.
Validates the LangGraph Platform RemoteGraph integration per ADR-048.
"""

from __future__ import annotations

import logging
import sys
from collections.abc import Callable
from pathlib import Path

# Keep helper stderr focused on assertion failures and tracebacks.
logging.disable(logging.CRITICAL)

# Ensure local source tree is importable
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

from cleveragents.infrastructure.database.postgresql import (  # noqa: E402
    PostgreSQLConnectionConfig,
    build_postgresql_url,
    is_postgresql_url,
)
from cleveragents.langgraph.remote_graph import (  # noqa: E402
    RemoteGraphConfig,
    RemoteGraphManager,
    RemoteGraphNotAvailableError,
)

# ---------------------------------------------------------------------------
# Subcommands
# ---------------------------------------------------------------------------


def manager_not_configured() -> None:
    """Verify RemoteGraphManager reports unavailable when no platform URL given."""
    manager = RemoteGraphManager()

    assert not manager.is_available, (
        "Expected manager.is_available=False when no platform URL given"
    )
    assert manager.platform_url is None, (
        f"Expected platform_url=None, got {manager.platform_url!r}"
    )

    # All operations should raise RemoteGraphNotAvailableError
    config = RemoteGraphConfig(
        graph_id="test-actor",
        platform_url="https://langgraph.example.com",
    )

    try:
        manager.register_graph(config)
        raise AssertionError(
            "Expected RemoteGraphNotAvailableError from register_graph"
        )
    except RemoteGraphNotAvailableError:
        pass

    try:
        manager.list_graphs()
        raise AssertionError("Expected RemoteGraphNotAvailableError from list_graphs")
    except RemoteGraphNotAvailableError:
        pass

    try:
        manager.invoke("test-actor", {})
        raise AssertionError("Expected RemoteGraphNotAvailableError from invoke")
    except RemoteGraphNotAvailableError:
        pass

    # health_check returns False (no exception)
    result = manager.health_check()
    assert result is False, f"Expected health_check=False, got {result!r}"

    print("remote-graph-manager-not-configured-ok")


def manager_configured() -> None:
    """Verify RemoteGraphManager is available when platform URL is given."""
    platform_url = "https://langgraph.example.com"
    manager = RemoteGraphManager(platform_url=platform_url)

    assert manager.is_available, (
        "Expected manager.is_available=True when platform URL is given"
    )
    assert manager.platform_url == platform_url, (
        f"Expected platform_url={platform_url!r}, got {manager.platform_url!r}"
    )

    # Initially no graphs registered
    graphs = manager.list_graphs()
    assert graphs == [], f"Expected empty graph list, got {graphs!r}"

    print("remote-graph-manager-configured-ok")


def graph_registration() -> None:
    """Verify graph registration and listing lifecycle."""
    platform_url = "https://langgraph.example.com"
    manager = RemoteGraphManager(platform_url=platform_url)

    # Register multiple graphs
    for graph_id in ("strategy-actor", "execution-actor", "estimation-actor"):
        config = RemoteGraphConfig(
            graph_id=graph_id,
            platform_url=platform_url,
        )
        manager.register_graph(config)

    # Verify all are listed in sorted order
    graphs = manager.list_graphs()
    expected = sorted(["strategy-actor", "execution-actor", "estimation-actor"])
    assert graphs == expected, f"Expected {expected!r}, got {graphs!r}"

    # Verify get_graph_config returns correct config
    config = manager.get_graph_config("strategy-actor")
    assert config.graph_id == "strategy-actor", (
        f"Expected graph_id='strategy-actor', got {config.graph_id!r}"
    )
    assert config.platform_url == platform_url, (
        f"Expected platform_url={platform_url!r}, got {config.platform_url!r}"
    )

    # Verify unregister removes the graph
    manager.unregister_graph("estimation-actor")
    graphs_after = manager.list_graphs()
    assert "estimation-actor" not in graphs_after, (
        f"Expected 'estimation-actor' to be removed, but found in {graphs_after!r}"
    )
    assert len(graphs_after) == 2, (
        f"Expected 2 graphs after unregister, got {len(graphs_after)}"
    )

    # Verify get_graph_config raises for unknown graph
    try:
        manager.get_graph_config("unknown-actor")
        raise AssertionError("Expected KeyError for unknown graph")
    except KeyError:
        pass

    # Verify unregister raises for unknown graph
    try:
        manager.unregister_graph("ghost-actor")
        raise AssertionError("Expected KeyError for unregistered graph")
    except KeyError:
        pass

    print("remote-graph-registration-ok")


def invoke_stub() -> None:
    """Verify invoke raises RemoteGraphNotAvailableError for stub implementation."""
    platform_url = "https://langgraph.example.com"
    manager = RemoteGraphManager(platform_url=platform_url)

    # Register a graph
    config = RemoteGraphConfig(
        graph_id="strategy-actor",
        platform_url=platform_url,
    )
    manager.register_graph(config)

    # Invoke should raise RemoteGraphNotAvailableError (stub)
    try:
        manager.invoke("strategy-actor", {"messages": []})
        raise AssertionError("Expected RemoteGraphNotAvailableError from invoke")
    except RemoteGraphNotAvailableError as exc:
        assert "strategy-actor" in str(exc.details), (
            f"Expected graph_id in error details, got {exc.details!r}"
        )

    # Invoke unregistered graph should raise KeyError
    try:
        manager.invoke("missing-actor", {})
        raise AssertionError("Expected KeyError for unregistered graph")
    except KeyError:
        pass

    # Invoke with thread_id should also raise RemoteGraphNotAvailableError
    try:
        manager.invoke("strategy-actor", {}, thread_id="thread-001")
        raise AssertionError(
            "Expected RemoteGraphNotAvailableError from invoke with thread_id"
        )
    except RemoteGraphNotAvailableError as exc:
        assert exc.details.get("thread_id") == "thread-001", (
            f"Expected thread_id in error details, got {exc.details!r}"
        )

    print("remote-graph-invoke-stub-ok")


def health_check() -> None:
    """Verify health_check returns False for stub implementation."""
    # Not configured
    manager_unconfigured = RemoteGraphManager()
    result = manager_unconfigured.health_check()
    assert result is False, (
        f"Expected health_check=False for unconfigured manager, got {result!r}"
    )

    # Configured (stub still returns False)
    manager_configured = RemoteGraphManager(
        platform_url="https://langgraph.example.com"
    )
    result = manager_configured.health_check()
    assert result is False, (
        f"Expected health_check=False for stub configured manager, got {result!r}"
    )

    print("remote-graph-health-check-ok")


def postgresql_config() -> None:
    """Verify PostgreSQLConnectionConfig validation and URL building."""
    # Valid config
    config = PostgreSQLConnectionConfig(
        host="db.example.com",
        database="cleveragents",
        username="app",
        password="secret",
    )
    assert config.host == "db.example.com", (
        f"Expected host='db.example.com', got {config.host!r}"
    )
    assert config.database == "cleveragents", (
        f"Expected database='cleveragents', got {config.database!r}"
    )
    assert config.username == "app", f"Expected username='app', got {config.username!r}"
    assert config.port == 5432, f"Expected port=5432, got {config.port}"
    assert config.ssl_mode == "prefer", (
        f"Expected ssl_mode='prefer', got {config.ssl_mode!r}"
    )
    assert config.pool_size == 5, f"Expected pool_size=5, got {config.pool_size}"
    assert config.max_overflow == 10, (
        f"Expected max_overflow=10, got {config.max_overflow}"
    )

    # Async URL
    async_url = config.to_url(async_driver=True)
    assert async_url.startswith("postgresql+asyncpg://"), (
        f"Expected async URL to start with 'postgresql+asyncpg://', got {async_url!r}"
    )
    assert "db.example.com" in async_url, f"Expected host in URL, got {async_url!r}"
    assert "cleveragents" in async_url, f"Expected database in URL, got {async_url!r}"

    # Sync URL
    sync_url = config.to_url(async_driver=False)
    assert sync_url.startswith("postgresql://"), (
        f"Expected sync URL to start with 'postgresql://', got {sync_url!r}"
    )

    # Custom port
    config_custom_port = PostgreSQLConnectionConfig(
        host="db.example.com",
        database="cleveragents",
        username="app",
        password="secret",
        port=5433,
    )
    assert config_custom_port.port == 5433, (
        f"Expected port=5433, got {config_custom_port.port}"
    )

    # build_postgresql_url helper
    url = build_postgresql_url(
        host="db.example.com",
        database="mydb",
        username="user",
        password="pass",
    )
    assert url.startswith("postgresql+asyncpg://"), (
        f"Expected async URL from build_postgresql_url, got {url!r}"
    )
    assert "db.example.com" in url, f"Expected host in URL, got {url!r}"
    assert "mydb" in url, f"Expected database in URL, got {url!r}"

    # Validation errors
    try:
        PostgreSQLConnectionConfig(
            host="",
            database="mydb",
            username="user",
            password="pass",
        )
        raise AssertionError("Expected validation error for empty host")
    except AssertionError:
        raise
    except Exception:
        pass

    try:
        PostgreSQLConnectionConfig(
            host="db.example.com",
            database="mydb",
            username="user",
            password="pass",
            port=0,
        )
        raise AssertionError("Expected validation error for port=0")
    except AssertionError:
        raise
    except Exception:
        pass

    try:
        PostgreSQLConnectionConfig(
            host="db.example.com",
            database="mydb",
            username="user",
            password="pass",
            pool_size=0,
        )
        raise AssertionError("Expected validation error for pool_size=0")
    except AssertionError:
        raise
    except Exception:
        pass

    print("postgresql-config-ok")


def postgresql_url_detection() -> None:
    """Verify is_postgresql_url correctly identifies PostgreSQL URLs."""
    # PostgreSQL URLs
    assert is_postgresql_url("postgresql://user:pass@host/db") is True, (
        "Expected True for postgresql:// URL"
    )
    assert is_postgresql_url("postgresql+asyncpg://user:pass@host/db") is True, (
        "Expected True for postgresql+asyncpg:// URL"
    )
    assert is_postgresql_url("POSTGRESQL://user:pass@host/db") is True, (
        "Expected True for uppercase POSTGRESQL:// URL"
    )

    # Non-PostgreSQL URLs
    assert is_postgresql_url("sqlite:///path/to/db.sqlite") is False, (
        "Expected False for sqlite:// URL"
    )
    assert is_postgresql_url("mysql://user:pass@host/db") is False, (
        "Expected False for mysql:// URL"
    )
    assert is_postgresql_url("") is False, "Expected False for empty string"

    print("postgresql-url-detection-ok")


def module_exports() -> None:
    """Verify RemoteGraph classes are exported from langgraph package."""
    from cleveragents.infrastructure.database import build_postgresql_url as bpu
    from cleveragents.infrastructure.database import is_postgresql_url as ipgu
    from cleveragents.langgraph import RemoteGraphConfig as RGC
    from cleveragents.langgraph import RemoteGraphManager as RGM
    from cleveragents.langgraph import RemoteGraphNotAvailableError as RGNAE

    # Verify classes are importable and functional
    manager = RGM()
    assert not manager.is_available, "Expected manager.is_available=False"

    config = RGC(
        graph_id="test",
        platform_url="https://langgraph.example.com",
    )
    assert config.graph_id == "test", (
        f"Expected graph_id='test', got {config.graph_id!r}"
    )

    # Verify error class
    err = RGNAE("test error")
    assert str(err) == "test error", f"Expected 'test error', got {str(err)!r}"

    # Verify database exports
    assert callable(bpu), "Expected build_postgresql_url to be callable"
    assert callable(ipgu), "Expected is_postgresql_url to be callable"

    print("module-exports-ok")


# ---------------------------------------------------------------------------
# Dispatcher
# ---------------------------------------------------------------------------

_COMMANDS: dict[str, Callable[[], None]] = {
    "manager-not-configured": manager_not_configured,
    "manager-configured": manager_configured,
    "graph-registration": graph_registration,
    "invoke-stub": invoke_stub,
    "health-check": health_check,
    "postgresql-config": postgresql_config,
    "postgresql-url-detection": postgresql_url_detection,
    "module-exports": module_exports,
}

if __name__ == "__main__":
    if len(sys.argv) < 2 or sys.argv[1] not in _COMMANDS:
        print(f"Usage: {sys.argv[0]} <{'|'.join(_COMMANDS)}>", file=sys.stderr)
        sys.exit(2)
    fn = _COMMANDS[sys.argv[1]]
    fn()
