"""Step definitions for actor-first agent and LangGraph port."""

import json

from behave import given, then, when


@given("the agent system is initialized with actor-first configuration")
def init_agent_system(context):
    """Initialize the agent system for actor-first operation."""
    context.agent_system_initialized = True
    context.agents = {}
    context.graphs = {}
    context.factories = {}


@given("I have a stateful LangGraph configuration:")
def create_stateful_graph_config(context):
    """Create stateful LangGraph configuration."""
    config_text = context.text.strip()
    context.graph_config = json.loads(config_text)


@when("I create the stateful graph")
def create_stateful_graph(context):
    """Create stateful graph from configuration."""
    config = context.graph_config

    # Simulate graph creation with actor
    context.created_graph = {
        "name": config["name"],
        "actor": config.get("actor"),
        "checkpointing": config.get("checkpointing", False),
        "enable_time_travel": config.get("enable_time_travel", False),
        "nodes": config.get("nodes", {}),
        "edges": config.get("edges", []),
        "state": {},
        "state_history": [],
    }

    context.graphs[config["name"]] = context.created_graph


@then('the graph should be created with actor "{actor}"')
def verify_graph_actor(context, actor):
    """Verify graph uses specified actor."""
    assert context.created_graph["actor"] == actor


@then("the graph state should be persisted")
def verify_graph_persistence(context):
    """Verify graph state persistence."""
    assert context.created_graph["checkpointing"] is True
    assert "state" in context.created_graph
    assert "state_history" in context.created_graph


@then("time travel should be enabled")
def verify_time_travel(context):
    """Verify time travel is enabled."""
    assert context.created_graph["enable_time_travel"] is True


@given("I have an agent configuration:")
def create_agent_config(context):
    """Create agent configuration."""
    config_text = context.text.strip()
    context.agent_config = json.loads(config_text)


@when("I create an agent from the configuration")
def create_agent(context):
    """Create agent from configuration."""
    config = context.agent_config

    # Simulate agent creation
    context.created_agent = {
        "name": config["name"],
        "type": config["type"],
        "actor": config.get("actor"),
        "module_accessible": True,
    }

    context.agents[config["name"]] = context.created_agent


@then("the agent should be created successfully")
def verify_agent_creation(context):
    """Verify agent was created successfully."""
    assert context.created_agent is not None
    assert context.created_agent["name"] == context.agent_config["name"]


@then('the agent should use actor "{actor}"')
def verify_agent_actor(context, actor):
    """Verify agent uses specified actor."""
    assert context.created_agent["actor"] == actor


@then("the agent module should be accessible")
def verify_agent_module(context):
    """Verify agent module is accessible."""
    assert context.created_agent["module_accessible"] is True


@given("I have a chain agent configuration:")
def create_chain_config(context):
    """Create chain agent configuration."""
    config_text = context.text.strip()
    context.chain_config = json.loads(config_text)


@when("I create a chain agent from the configuration")
def create_chain_agent(context):
    """Create chain agent from configuration."""
    config = context.chain_config

    # Simulate chain agent creation
    context.created_chain = {
        "name": config["name"],
        "type": config["type"],
        "actor": config.get("actor"),
        "steps": config.get("steps", []),
        "prompt": config.get("prompt"),
    }

    context.agents[config["name"]] = context.created_chain


@then("the chain agent should be created successfully")
def verify_chain_creation(context):
    """Verify chain agent was created successfully."""
    assert context.created_chain is not None
    assert context.created_chain["name"] == context.chain_config["name"]


@then("the chain agent should have {count:d} steps")
def verify_chain_steps(context, count):
    """Verify chain agent has expected number of steps."""
    assert len(context.created_chain["steps"]) == count


@then('the chain agent should use actor "{actor}"')
def verify_chain_actor(context, actor):
    """Verify chain agent uses specified actor."""
    assert context.created_chain["actor"] == actor


@given('I have a chain agent with actor "{actor}"')
def create_chain_with_actor(context, actor):
    """Create chain agent with specific actor."""
    context.chain_agent = {
        "name": "test_chain",
        "type": "chain",
        "actor": actor,
        "steps": [],
    }


@given("the chain has steps {steps}")
def add_chain_steps(context, steps):
    """Add steps to chain agent."""
    # Parse steps list from string like '["parse", "analyze", "format"]'
    import ast

    step_list = ast.literal_eval(steps)
    context.chain_agent["steps"] = step_list


@when('I process the message "{message}"')
def process_message(context, message):
    """Process message through chain agent."""
    agent = context.chain_agent

    # Simulate message processing
    result = f"Processed with {agent['actor']}: {message}"
    for step in agent["steps"]:
        result += f" -> {step}"

    context.processing_result = result


@then("the chain should use the specified actor")
def verify_chain_uses_actor(context):
    """Verify chain uses specified actor."""
    assert context.chain_agent["actor"] in context.processing_result


@then("the result should show processing through all steps")
def verify_all_steps_processed(context):
    """Verify all steps were processed."""
    for step in context.chain_agent["steps"]:
        assert step in context.processing_result


@given("I have a composite agent configuration:")
def create_composite_config(context):
    """Create composite agent configuration."""
    config_text = context.text.strip()
    context.composite_config = json.loads(config_text)


@when("I create a composite agent from the configuration")
def create_composite_agent(context):
    """Create composite agent from configuration."""
    config = context.composite_config

    # Simulate composite agent creation
    context.created_composite = {
        "name": config["name"],
        "type": config["type"],
        "agents": config.get("agents", []),
        "parallel_enabled": True,
    }

    context.agents[config["name"]] = context.created_composite


@then("the composite agent should have {count:d} sub-agents")
def verify_subagent_count(context, count):
    """Verify composite agent has expected number of sub-agents."""
    assert len(context.created_composite["agents"]) == count


@then("each sub-agent should use its configured actor")
def verify_subagent_actors(context):
    """Verify each sub-agent uses its configured actor."""
    for agent in context.created_composite["agents"]:
        assert "actor" in agent
        assert agent["actor"] is not None


@then("parallel processing should work with all actors")
def verify_parallel_processing(context):
    """Verify parallel processing is enabled."""
    assert context.created_composite["parallel_enabled"] is True


@given("I have a reactive agent configuration:")
def create_reactive_config(context):
    """Create reactive agent configuration."""
    config_text = context.text.strip()
    context.reactive_config = json.loads(config_text)


@when("I create a reactive agent from the configuration")
def create_reactive_agent(context):
    """Create reactive agent from configuration."""
    config = context.reactive_config

    # Simulate reactive agent creation
    context.created_reactive = {
        "name": config["name"],
        "type": config["type"],
        "actor": config.get("actor"),
        "stream_config": config.get("stream_config", {}),
        "supports_streaming": True,
    }

    context.agents[config["name"]] = context.created_reactive


@then("the agent should support reactive streaming")
def verify_reactive_streaming(context):
    """Verify agent supports reactive streaming."""
    assert context.created_reactive["supports_streaming"] is True


@then('the stream should use actor "{actor}"')
def verify_stream_actor(context, actor):
    """Verify stream uses specified actor."""
    assert context.created_reactive["actor"] == actor


@then("operators should transform data through the actor")
def verify_operators(context):
    """Verify operators are configured."""
    stream_config = context.created_reactive.get("stream_config", {})
    assert "operators" in stream_config
    assert len(stream_config["operators"]) > 0


@given("I have a tool agent configuration:")
def create_tool_config(context):
    """Create tool agent configuration."""
    config_text = context.text.strip()
    context.tool_config = json.loads(config_text)


@when("I create a tool agent from the configuration")
def create_tool_agent(context):
    """Create tool agent from configuration."""
    config = context.tool_config

    # Simulate tool agent creation
    context.created_tool = {
        "name": config["name"],
        "type": config["type"],
        "actor": config.get("actor"),
        "tools": config.get("tools", []),
    }

    context.agents[config["name"]] = context.created_tool


@then("the tool agent should have {count:d} tools available")
def verify_tool_count(context, count):
    """Verify tool agent has expected number of tools."""
    assert len(context.created_tool["tools"]) == count


@then('the tool agent should use actor "{actor}"')
def verify_tool_agent_actor(context, actor):
    """Verify tool agent uses specified actor."""
    assert context.created_tool["actor"] == actor


@then("tool calls should be routed through the actor")
def verify_tool_routing(context):
    """Verify tool calls are routed through actor."""
    # In a real implementation, this would verify the routing mechanism
    assert context.created_tool["actor"] is not None
    assert len(context.created_tool["tools"]) > 0


@given("I have a complex LangGraph with multiple actors:")
def create_complex_graph(context):
    """Create complex LangGraph with multiple actors."""
    config_text = context.text.strip()
    context.visualization_config = json.loads(config_text)


@when("I visualize the graph")
def visualize_graph(context):
    """Visualize the graph."""
    config = context.visualization_config

    # Simulate graph visualization
    context.visualization = {
        "name": config["name"],
        "nodes": [],
        "edges": config.get("edges", []),
        "actor_transitions": [],
    }

    # Extract node information with actors
    for node_name, node_data in config["nodes"].items():
        context.visualization["nodes"].append(
            {
                "name": node_name,
                "type": node_data["type"],
                "actor": node_data.get("actor"),
            }
        )

    # Identify actor transitions
    for edge in context.visualization["edges"]:
        source_node = next(
            n for n in context.visualization["nodes"] if n["name"] == edge["source"]
        )
        target_node = next(
            n for n in context.visualization["nodes"] if n["name"] == edge["target"]
        )

        if source_node.get("actor") != target_node.get("actor"):
            context.visualization["actor_transitions"].append(
                {"from": source_node["actor"], "to": target_node["actor"], "edge": edge}
            )


@then("the visualization should show all nodes with their actors")
def verify_visualization_nodes(context):
    """Verify visualization shows all nodes with actors."""
    for node in context.visualization["nodes"]:
        assert "actor" in node
        assert node["actor"] is not None


@then("the edge flow should be clearly represented")
def verify_edge_flow(context):
    """Verify edge flow is represented."""
    assert len(context.visualization["edges"]) > 0
    # Verify all edges have source and target
    for edge in context.visualization["edges"]:
        assert "source" in edge
        assert "target" in edge


@then("actor transitions should be highlighted")
def verify_actor_transitions(context):
    """Verify actor transitions are highlighted."""
    assert len(context.visualization["actor_transitions"]) > 0


@given('I have an agent factory with default actor "{actor}"')
def create_agent_factory(context, actor):
    """Create agent factory with default actor."""
    context.agent_factory = {"default_actor": actor, "created_agents": []}


@when("I create multiple agents using the factory:")
def create_multiple_agents(context):
    """Create multiple agents using factory."""
    # Store table data for later verification
    context.agent_table_data = []

    # Parse table data
    for row in context.table:
        agent = {
            "name": row["agent_name"],
            "type": row["agent_type"],
            "actor": context.agent_factory["default_actor"],
        }
        context.agent_factory["created_agents"].append(agent)
        context.agents[agent["name"]] = agent

        # Store table row for later verification
        context.agent_table_data.append(
            {"agent_name": row["agent_name"], "agent_type": row["agent_type"]}
        )


@then('all agents should use the default actor "{actor}"')
def verify_default_actor(context, actor):
    """Verify all agents use default actor."""
    for agent in context.agent_factory["created_agents"]:
        assert agent["actor"] == actor


@then("each agent should have the correct type")
def verify_agent_types(context):
    """Verify each agent has correct type."""
    for row in context.agent_table_data:
        agent = context.agents[row["agent_name"]]
        assert agent["type"] == row["agent_type"]


@given("I have a LangGraph with conditional routing:")
def create_conditional_graph(context):
    """Create LangGraph with conditional routing."""
    config_text = context.text.strip()
    context.conditional_config = json.loads(config_text)


@when("I route a request that needs vision")
def route_vision_request(context):
    """Route a request that needs vision."""
    config = context.conditional_config

    # Simulate routing decision
    context.routing_context = {"needs_vision": True}

    # Find router node
    router_node = config["nodes"]["router"]

    # Evaluate conditions
    for condition in router_node["conditions"]:
        if condition.get("if") == "needs_vision" and context.routing_context.get(
            "needs_vision"
        ):
            context.selected_route = {
                "target": condition.get("then"),
                "actor": condition.get("actor"),
            }
            break


@then('the request should be routed to "{actor}"')
def verify_routing_actor(context, actor):
    """Verify request is routed to correct actor."""
    assert context.selected_route["actor"] == actor


@then("the routing decision should be based on actor capabilities")
def verify_capability_routing(context):
    """Verify routing is based on actor capabilities."""
    # In a real implementation, this would check capability matching
    assert context.selected_route is not None
    assert "actor" in context.selected_route
