from typing import List, Optional
from .agent import Agent
from .memory import Memory
from .result import BridgeResult, TraceStep


class Bridge:
    """
    Connects multiple agents and orchestrates communication between them.

    Usage:
        bridge = Bridge([agent_a, agent_b, agent_c])
        result = bridge.run("Your task here")

        # Direct agent-to-agent message
        response = bridge.send(from_agent="researcher", to_agent="writer", message="Here is my research...")

        # Access result
        print(result.final)        # Final answer
        print(result.summary())    # Full trace
    """

    def __init__(self, agents: List[Agent], memory: bool = True, verbose: bool = False):
        if not agents:
            raise ValueError("Bridge requires at least one agent.")

        self.agents = {agent.name: agent for agent in agents}
        self.use_memory = memory
        self.verbose = verbose
        self.memory = Memory()

    def run(self, task: str) -> BridgeResult:
        """
        Runs the task sequentially through all agents.
        Each agent gets the original task + all previous agents' responses as context.
        """
        self.memory.clear()
        trace = []
        agents_used = []

        # Add original task to memory
        self.memory.add("user", task, agent="user")
        trace.append(TraceStep(agent="user", role="input", content=task))

        if self.verbose:
            print(f"\n🧠 Synapse Bridge starting with task:\n{task}\n")
            print(f"Agents in pipeline: {' → '.join(self.agents.keys())}\n")

        current_input = task

        for agent_name, agent in self.agents.items():
            if self.verbose:
                print(f"🤖 [{agent_name}] thinking...")

            # Build messages: original task + full conversation history
            messages = self.memory.get_messages()

            # Get agent response
            response = agent.complete(messages)

            # Store in memory and trace
            self.memory.add("assistant", response, agent=agent_name)
            trace.append(TraceStep(agent=agent_name, role="output", content=response))
            agents_used.append(agent_name)

            # Next agent gets this response as context
            self.memory.add(
                "user",
                f"The previous agent '{agent_name}' responded. Now continue with the original task using this context.",
                agent="system"
            )

            if self.verbose:
                print(f"✅ [{agent_name}] done.\n")

            current_input = response

        return BridgeResult(
            final=current_input,
            trace=trace,
            agents_used=agents_used
        )

    def send(self, from_agent: str, to_agent: str, message: str) -> str:
        """
        Directly send a message from one agent to another.
        Returns the response from the target agent.
        """
        if to_agent not in self.agents:
            raise ValueError(f"Agent '{to_agent}' not found in bridge. Available: {list(self.agents.keys())}")

        if self.verbose:
            print(f"📨 [{from_agent}] → [{to_agent}]: {message[:100]}...")

        target = self.agents[to_agent]
        messages = [{"role": "user", "content": f"Message from agent '{from_agent}':\n\n{message}"}]
        response = target.complete(messages)

        if self.verbose:
            print(f"✅ [{to_agent}] responded.\n")

        return response

    def add_agent(self, agent: Agent):
        """Add a new agent to the bridge dynamically."""
        self.agents[agent.name] = agent

    def remove_agent(self, name: str):
        """Remove an agent from the bridge."""
        if name in self.agents:
            del self.agents[name]

    def __repr__(self):
        return f"Bridge(agents={list(self.agents.keys())}, memory={self.use_memory})"
