"""Tests for ingesting LangGraph scripts and resolving entrypoints."""

from __future__ import annotations
import textwrap
import pytest
from orcheo.graph.builder import build_graph
from orcheo.graph.ingestion import (
    LANGGRAPH_SCRIPT_FORMAT,
    ScriptIngestionError,
    ingest_langgraph_script,
)


def test_ingest_script_with_entrypoint() -> None:
    script = textwrap.dedent(
        """
        from langgraph.graph import StateGraph
        from orcheo.graph.state import State
        from orcheo.nodes.rss import RSSNode

        def build_graph():
            graph = StateGraph(State)
            graph.add_node("rss", RSSNode(name="rss", sources=["https://example.com/feed"]))
            graph.set_entry_point("rss")
            graph.set_finish_point("rss")
            return graph
        """
    )

    payload = ingest_langgraph_script(script, entrypoint="build_graph")

    assert payload["format"] == LANGGRAPH_SCRIPT_FORMAT
    assert payload["entrypoint"] == "build_graph"
    summary = payload["summary"]
    assert summary["edges"] == [("START", "rss"), ("rss", "END")]
    assert summary["nodes"][0]["type"] == "RSSNode"

    graph = build_graph(payload)
    assert set(graph.nodes.keys()) == {"rss"}


def test_ingest_script_without_entrypoint_auto_discovers_graph() -> None:
    script = textwrap.dedent(
        """
        from langgraph.graph import StateGraph
        from orcheo.graph.state import State

        graph = StateGraph(State)
        graph.add_node("first", lambda state: state)
        graph.set_entry_point("first")
        graph.set_finish_point("first")
        """
    )

    payload = ingest_langgraph_script(script)

    assert payload["entrypoint"] is None
    summary = payload["summary"]
    assert summary["edges"] == [("START", "first"), ("first", "END")]


def test_ingest_script_with_multiple_candidates_requires_entrypoint() -> None:
    script = textwrap.dedent(
        """
        from langgraph.graph import StateGraph
        from orcheo.graph.state import State

        first = StateGraph(State)
        second = StateGraph(State)
        """
    )

    with pytest.raises(ScriptIngestionError):
        ingest_langgraph_script(script)


def test_ingest_script_rejects_forbidden_imports() -> None:
    script = textwrap.dedent(
        """
        import os
        from langgraph.graph import StateGraph
        from orcheo.graph.state import State

        graph = StateGraph(State)
        graph.set_entry_point("first")
        graph.set_finish_point("first")
        """
    )

    with pytest.raises(ScriptIngestionError):
        ingest_langgraph_script(script)


def test_ingest_script_rejects_relative_imports() -> None:
    script = "from .foo import bar"

    with pytest.raises(ScriptIngestionError):
        ingest_langgraph_script(script)


def test_ingest_script_missing_entrypoint_errors() -> None:
    script = textwrap.dedent(
        """
        from langgraph.graph import StateGraph
        from orcheo.graph.state import State

        graph = StateGraph(State)
        graph.set_entry_point("first")
        graph.set_finish_point("first")
        """
    )

    with pytest.raises(ScriptIngestionError):
        ingest_langgraph_script(script, entrypoint="missing")


def test_ingest_script_without_candidates_errors() -> None:
    with pytest.raises(ScriptIngestionError):
        ingest_langgraph_script("value = 42")


def test_ingest_script_entrypoint_requires_arguments() -> None:
    script = textwrap.dedent(
        """
        from langgraph.graph import StateGraph
        from orcheo.graph.state import State

        def build_graph(name: str):
            graph = StateGraph(State)
            graph.set_entry_point("first")
            graph.set_finish_point("first")
            return graph
        """
    )

    with pytest.raises(ScriptIngestionError):
        ingest_langgraph_script(script, entrypoint="build_graph")


def test_ingest_script_handles_compiled_graph_entrypoint() -> None:
    script = textwrap.dedent(
        """
        from langgraph.graph import StateGraph
        from orcheo.graph.state import State

        graph = StateGraph(State)
        graph.add_node("first", lambda state: state)
        graph.set_entry_point("first")
        graph.set_finish_point("first")
        compiled = graph.compile()
        """
    )

    payload = ingest_langgraph_script(script, entrypoint="compiled")

    summary = payload["summary"]
    assert summary["edges"] == [("START", "first"), ("first", "END")]


def test_ingest_script_entrypoint_not_resolvable() -> None:
    script = textwrap.dedent(
        """
        class Dummy:
            pass

        candidate = Dummy()
        """
    )

    with pytest.raises(ScriptIngestionError):
        ingest_langgraph_script(script, entrypoint="candidate")
