# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
MCP Integration Examples

Demonstrates how to use MCP (Model Context Protocol) with Familiar.
"""

import asyncio
import os
from pathlib import Path

# Example 1: Basic MCP Setup
# --------------------------


async def example_basic_setup():
    """
    Basic MCP integration setup.

    This shows the minimal code needed to connect to MCP servers
    and get tools into Familiar.
    """
    from familiar.core.mcp import (
        MCPConfig,
        MCPManager,
        MCPServerConfig,
        MCPToolBridge,
        MCPTransport,
    )
    from familiar.core.tools import get_tool_registry

    # Create configuration
    config = MCPConfig(
        enabled=True,
        servers=[
            # Filesystem server - access local files
            MCPServerConfig(
                name="filesystem",
                transport=MCPTransport.STDIO,
                command="uvx",
                args=["mcp-server-filesystem", str(Path.home())],
            ),
        ],
    )

    # Create manager and connect
    manager = MCPManager(config)
    await manager.connect_all()

    # Get Familiar's tool registry
    registry = get_tool_registry()

    # Create bridge and sync tools
    bridge = MCPToolBridge(manager, registry)
    await bridge.sync_tools()

    # Now registry has MCP tools!
    print(f"Total tools available: {len(registry.tools)}")

    # Clean up
    await manager.disconnect_all()


# Example 2: GitHub Integration
# ----------------------------


async def example_github_integration():
    """
    Integrate GitHub via MCP.

    Requires: GITHUB_TOKEN environment variable
    """
    from familiar.core.mcp import (
        MCPConfig,
        MCPManager,
        MCPServerConfig,
        MCPTransport,
    )

    if not os.environ.get("GITHUB_TOKEN"):
        print("Set GITHUB_TOKEN environment variable first")
        return

    config = MCPConfig(
        enabled=True,
        servers=[
            MCPServerConfig(
                name="github",
                transport=MCPTransport.STDIO,
                command="npx",
                args=["-y", "@modelcontextprotocol/server-github"],
                env={"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]},
            ),
        ],
    )

    async with MCPManager(config) as manager:
        # List available tools
        tools = await manager.list_all_tools()
        print(f"GitHub tools available: {len(tools)}")

        for tool in tools:
            print(f"  - {tool.name}: {tool.description[:60]}...")

        # Example: Search repositories
        if any(t.name.endswith("search_repositories") for t in tools):
            result = await manager.call_tool(
                "github:search_repositories", {"query": "familiar agent framework"}
            )
            print(f"\nSearch result: {result.text[:200]}...")


# Example 3: Multiple Servers
# --------------------------


async def example_multiple_servers():
    """
    Connect to multiple MCP servers simultaneously.
    """
    from familiar.core.mcp import (
        MCPConfig,
        MCPManager,
        MCPServerConfig,
        MCPTransport,
        get_common_server,
    )

    # Use pre-configured server templates
    config = MCPConfig(
        enabled=True,
        servers=[
            # Use common server template
            get_common_server("filesystem", args=["mcp-server-filesystem", "/tmp"]),
            # Custom SQLite server
            MCPServerConfig(
                name="my-database",
                transport=MCPTransport.STDIO,
                command="uvx",
                args=["mcp-server-sqlite", "--db", "/tmp/test.db"],
            ),
        ],
    )

    manager = MCPManager(config)

    # Connect and get status
    results = await manager.connect_all()

    for server_name, success in results.items():
        status = "✓" if success else "✗"
        print(f"{status} {server_name}")

    # Get all tools across all servers
    all_tools = await manager.list_all_tools()

    # Group by server
    by_server = {}
    for tool in all_tools:
        server = tool.name.split(":")[0]
        by_server.setdefault(server, []).append(tool)

    for server, tools in by_server.items():
        print(f"\n{server}: {len(tools)} tools")

    await manager.disconnect_all()


# Example 4: Security Configuration
# --------------------------------


async def example_security():
    """
    Configure MCP with security restrictions.
    """
    from familiar.core.mcp import MCPConfig, MCPServerConfig, MCPTransport

    # Server with restricted tools
    restricted_server = MCPServerConfig(
        name="restricted-fs",
        transport=MCPTransport.STDIO,
        command="uvx",
        args=["mcp-server-filesystem", "/tmp"],
        # Security settings
        trust_level="untrusted",  # Lower trust = more confirmations
        requires_confirmation=True,  # Always ask before executing
        # Only allow specific tools
        allowed_tools=["read_file", "list_directory"],
        # Or block specific tools
        # blocked_tools=["delete_file", "write_file"],
    )

    # Global config with security settings (example code — intentionally not used)
    config = MCPConfig(  # noqa: F841
        enabled=True,
        servers=[restricted_server],
        # Require confirmation for all untrusted servers
        require_confirmation_untrusted=True,
    )

    print("Security configuration:")
    print(f"  - Trust level: {restricted_server.trust_level}")
    print(f"  - Requires confirmation: {restricted_server.requires_confirmation}")
    print(f"  - Allowed tools: {restricted_server.allowed_tools}")


# Example 5: YAML Configuration
# ----------------------------


def example_yaml_config():
    """
    Load MCP configuration from YAML file.
    """

    # Example YAML content (would be in ~/.familiar/mcp.yaml):
    yaml_content = """
mcp:
  enabled: true
  tool_prefix_separator: ":"
  connect_timeout: 30.0
  reconnect_on_failure: true

  servers:
    - name: filesystem
      transport: stdio
      command: uvx
      args:
        - mcp-server-filesystem
        - /home/user/documents
      enabled: true

    - name: github
      transport: stdio
      command: npx
      args:
        - "-y"
        - "@modelcontextprotocol/server-github"
      env:
        GITHUB_TOKEN: "${GITHUB_TOKEN}"
      enabled: true
      trust_level: trusted

    - name: postgres
      transport: stdio
      command: uvx
      args:
        - mcp-server-postgres
      env:
        DATABASE_URL: "${DATABASE_URL}"
      enabled: false
      requires_confirmation: true
"""

    print("Example YAML configuration:")
    print(yaml_content)

    # To load:
    # config = MCPConfig.from_yaml("~/.familiar/mcp.yaml")


# Example 6: Dynamic Server Management
# -----------------------------------


async def example_dynamic_servers():
    """
    Add and remove servers at runtime.
    """
    from familiar.core.mcp import (
        MCPConfig,
        MCPManager,
        MCPServerConfig,
        MCPTransport,
    )

    # Start with empty config
    config = MCPConfig(enabled=True, servers=[])
    manager = MCPManager(config)

    # Add server dynamically
    new_server = MCPServerConfig(
        name="dynamic-fs",
        transport=MCPTransport.STDIO,
        command="uvx",
        args=["mcp-server-filesystem", "/tmp"],
    )

    # Add and connect
    await manager.add_server(new_server, connect=True)
    print(f"Added server: {new_server.name}")
    print(f"Connected servers: {manager.get_connected_servers()}")

    # List tools from new server
    tools = await manager.list_server_tools("dynamic-fs")
    print(f"Tools: {[t.name for t in tools]}")

    # Remove server
    await manager.remove_server("dynamic-fs")
    print(f"Removed server. Remaining: {manager.get_connected_servers()}")


# Example 7: Event Callbacks
# -------------------------


async def example_callbacks():
    """
    React to MCP events with callbacks.
    """
    from familiar.core.mcp import MCPConfig, MCPManager, MCPServerConfig, MCPTransport

    config = MCPConfig(
        enabled=True,
        servers=[
            MCPServerConfig(
                name="test",
                transport=MCPTransport.STDIO,
                command="echo",  # Won't actually work, just for demo
                args=["test"],
                auto_connect=False,
            ),
        ],
    )

    manager = MCPManager(config)

    # Register callbacks
    def on_connect(server_name):
        print(f"🟢 Server connected: {server_name}")

    def on_disconnect(server_name, reason):
        print(f"🔴 Server disconnected: {server_name} ({reason or 'normal'})")

    def on_tools_changed(server_name, tools):
        print(f"🔧 Tools updated for {server_name}: {len(tools)} tools")

    manager.on_connect(on_connect)
    manager.on_disconnect(on_disconnect)
    manager.on_tools_changed(on_tools_changed)

    print("Callbacks registered!")


# Example 8: Error Handling
# ------------------------


async def example_error_handling():
    """
    Handle MCP errors gracefully.
    """
    from familiar.core.mcp import (
        MCPClientError,
        MCPConfig,
        MCPConnectionError,
        MCPManager,
        MCPServerConfig,
        MCPTransport,
    )
    from familiar.core.mcp.client import MCPTimeoutError

    config = MCPConfig(
        enabled=True,
        servers=[
            MCPServerConfig(
                name="unreliable",
                transport=MCPTransport.STDIO,
                command="nonexistent-command",  # Will fail
                args=[],
            ),
        ],
    )

    manager = MCPManager(config)

    try:
        results = await manager.connect_all()

        for name, success in results.items():
            if not success:
                info = manager.get_server_info(name)
                print(f"Failed to connect to {name}: {info['error']}")

    except MCPConnectionError as e:
        print(f"Connection error: {e}")

    except MCPTimeoutError as e:
        print(f"Timeout: {e}")

    except MCPClientError as e:
        print(f"MCP error: {e}")

    finally:
        await manager.disconnect_all()


# Example 9: Integration with Agent
# --------------------------------


async def example_agent_integration():
    """
    Full integration with Familiar agent.

    This shows how MCP tools become available to the agent.
    """
    from familiar.core.mcp import (
        MCPConfig,
        MCPManager,
        MCPServerConfig,
        MCPToolBridge,
        MCPTransport,
    )
    from familiar.core.tools import get_tool_registry
    # from familiar.core.agent import Agent  # Would import actual agent

    # Setup MCP
    mcp_config = MCPConfig(
        enabled=True,
        servers=[
            MCPServerConfig(
                name="filesystem",
                transport=MCPTransport.STDIO,
                command="uvx",
                args=["mcp-server-filesystem", "/tmp"],
            ),
        ],
    )

    # Connect MCP
    manager = MCPManager(mcp_config)
    await manager.connect_all()

    # Get registry and bridge
    registry = get_tool_registry()
    bridge = MCPToolBridge(manager, registry)
    await bridge.sync_tools()

    # Now the agent can use MCP tools
    # agent = Agent(tools=registry)
    # response = await agent.chat("List files in /tmp using the filesystem tool")

    # The agent would see tool "filesystem:list_directory" and can call it
    print("MCP tools registered with agent!")
    print(f"Available tools: {list(registry.tools.keys())}")

    await manager.disconnect_all()


# Run examples
if __name__ == "__main__":
    print("=" * 60)
    print("MCP Integration Examples")
    print("=" * 60)

    # Run sync examples
    print("\n--- Example: YAML Config ---")
    example_yaml_config()

    print("\n--- Example: Security Config ---")
    asyncio.run(example_security())

    print("\n--- Example: Callbacks ---")
    asyncio.run(example_callbacks())

    print("\n--- Example: Error Handling ---")
    asyncio.run(example_error_handling())

    print("\n" + "=" * 60)
    print("See source code for more examples!")
    print("=" * 60)
