"""CLI entry point for the application."""

import argparse
import asyncio
import sys
from typing import Any

from dotenv import load_dotenv
from pydantic_ai import Agent

# Load environment variables from .env file
load_dotenv()


def main() -> int:
    """Main CLI entry point."""
    parser = argparse.ArgumentParser(
        description="PydanticAI Multi-Agent Framework",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    # Server command
    server_parser = subparsers.add_parser("serve", help="Start the API server")
    server_parser.add_argument("--host", default="0.0.0.0", help="Host to bind to")
    server_parser.add_argument("--port", type=int, default=8000, help="Port to bind to")
    server_parser.add_argument("--reload", action="store_true", help="Enable auto-reload")

    # Chat command
    chat_parser = subparsers.add_parser("chat", help="Interactive chat mode")
    chat_parser.add_argument(
        "--agent",
        default="router",
        choices=["router", "research", "analyst", "code", "writer", "support"],
        help="Agent to use",
    )

    # Query command
    query_parser = subparsers.add_parser("query", help="Run a single query")
    query_parser.add_argument("prompt", help="The prompt to send")
    query_parser.add_argument(
        "--agent",
        default="router",
        choices=["router", "research", "analyst", "code", "writer", "support"],
        help="Agent to use",
    )

    # Database commands
    subparsers.add_parser("db-migrate", help="Run database migrations")

    # MCP server command
    mcp_parser = subparsers.add_parser("mcp-serve", help="Run MCP server (stdio transport)")
    mcp_parser.add_argument(
        "--transport",
        choices=["stdio", "sse"],
        default="stdio",
        help="Transport to use (default: stdio)",
    )
    mcp_parser.add_argument("--host", default="127.0.0.1", help="Host for SSE transport")
    mcp_parser.add_argument("--port", type=int, default=8001, help="Port for SSE transport")

    args = parser.parse_args()

    if args.command == "serve":
        return run_server(args)
    elif args.command == "chat":
        return asyncio.run(run_chat(args))
    elif args.command == "query":
        return asyncio.run(run_query(args))
    elif args.command == "db-migrate":
        return asyncio.run(run_db_migrate())
    elif args.command == "mcp-serve":
        return run_mcp_server(args)
    else:
        parser.print_help()
        return 0


def run_server(args: argparse.Namespace) -> int:
    """Start the API server."""
    try:
        import uvicorn

        uvicorn.run(
            "pydanticai_multiagent.api.app:app",
            host=args.host,
            port=args.port,
            reload=args.reload,
        )
        return 0
    except ImportError:
        print("Error: uvicorn not installed. Run: pip install uvicorn")
        return 1


def run_mcp_server(args: argparse.Namespace) -> int:
    """Run the MCP server for Claude Desktop, Cursor, etc."""
    try:
        from pydanticai_multiagent.mcp import mcp_server

        print(f"Starting MCP server with {args.transport} transport...")

        if args.transport == "stdio":
            # Stdio transport for local integrations (Claude Desktop)
            mcp_server.run()
        else:
            # SSE transport for network access
            mcp_server.run(transport="sse", host=args.host, port=args.port)

        return 0
    except ImportError as e:
        print(f"Error: MCP dependencies not installed: {e}")
        print("Run: pip install fastmcp")
        return 1
    except Exception as e:
        print(f"Error running MCP server: {e}")
        return 1


async def run_db_migrate() -> int:
    """Run database migrations."""
    from pydanticai_multiagent.config import settings
    from pydanticai_multiagent.db import run_migrations

    if not settings.database_url or settings.database_url == "postgresql://localhost:5432/myapp":
        print("Error: DATABASE_URL not configured.")
        print("Set DATABASE_URL in .env file with your Supabase connection string.")
        return 1

    print("Running migrations against database...")
    try:
        applied = await run_migrations(settings.database_url)
        if applied:
            print(f"Applied {len(applied)} migration(s):")
            for name in applied:
                print(f"  - {name}")
        else:
            print("No new migrations to apply.")
        return 0
    except Exception as e:
        print(f"Error running migrations: {e}")
        return 1


async def get_agent_and_deps(agent_name: str) -> tuple[Agent[Any, Any], Any]:
    """Get the agent and appropriate dependencies based on agent name.

    Uses real Supabase database if DATABASE_URL is configured,
    otherwise falls back to MockDatabase.
    """
    from pydanticai_multiagent.agents import (
        analyst_agent,
        code_agent,
        research_agent,
        router_agent,
        support_agent,
        writer_agent,
    )
    from pydanticai_multiagent.config import settings

    # Determine if we should use real database
    db_url = settings.database_url
    use_real_db = db_url and db_url.startswith("postgresql://") and "supabase" in db_url

    if use_real_db:
        from pydanticai_multiagent.db import create_pool
        from pydanticai_multiagent.dependencies import AuthDeps, BaseDeps, SearchDeps
        from pydanticai_multiagent.dependencies.mocks import (
            MockCache,
            MockHttpClient,
            MockVectorStore,
        )

        db = await create_pool(db_url)

        def make_base_deps(user_id: str | None = None) -> BaseDeps:
            return BaseDeps(
                http_client=MockHttpClient(),
                db=db,
                cache=MockCache(),
                user_id=user_id,
            )

        def make_search_deps(user_id: str | None = None) -> SearchDeps:
            return SearchDeps(
                http_client=MockHttpClient(),
                db=db,
                cache=MockCache(),
                user_id=user_id,
                vector_store=MockVectorStore(),
                search_api_key="mock-api-key",
            )

        def make_auth_deps(user_id: str | None = None) -> AuthDeps:
            return AuthDeps(
                http_client=MockHttpClient(),
                db=db,
                cache=MockCache(),
                user_id=user_id,
                user_roles=["user"],
                permissions=["read:data"],
            )

        agents = {
            "router": (router_agent, make_search_deps),
            "research": (research_agent, make_search_deps),
            "analyst": (analyst_agent, make_base_deps),
            "code": (code_agent, make_base_deps),
            "writer": (writer_agent, make_base_deps),
            "support": (support_agent, make_auth_deps),
        }
    else:
        from pydanticai_multiagent.dependencies import (
            create_mock_auth_deps,
            create_mock_base_deps,
            create_mock_search_deps,
        )

        agents = {
            "router": (router_agent, create_mock_search_deps),
            "research": (research_agent, create_mock_search_deps),
            "analyst": (analyst_agent, create_mock_base_deps),
            "code": (code_agent, create_mock_base_deps),
            "writer": (writer_agent, create_mock_base_deps),
            "support": (support_agent, create_mock_auth_deps),
        }

    agent, deps_factory = agents[agent_name]
    return agent, deps_factory(user_id="cli-user")


def format_response(agent_name: str, result: Any) -> str:
    """Format the agent response for display."""
    output = result.output

    # Handle different output types
    if hasattr(output, "format_with_sources"):
        # ResearchResult
        return output.format_with_sources()
    elif hasattr(output, "model_dump_json"):
        # Pydantic model
        return output.model_dump_json(indent=2)
    elif hasattr(output, "explanation"):
        # CodeResponse
        response = f"**Explanation:**\n{output.explanation}"
        if output.code:
            lang = output.language or ""
            response += f"\n\n**Code:**\n```{lang}\n{output.code}\n```"
        if output.suggestions:
            response += "\n\n**Suggestions:**\n" + "\n".join(f"- {s}" for s in output.suggestions)
        return response
    elif hasattr(output, "answer"):
        # SupportResponse
        response = output.answer
        if output.escalate:
            response += f"\n\n[Escalated: {output.escalation_reason}]"
        if output.follow_up_actions:
            response += "\n\nFollow-up:\n" + "\n".join(f"- {a}" for a in output.follow_up_actions)
        return response
    else:
        # String or other
        return str(output)


async def run_chat(args: argparse.Namespace) -> int:
    """Run interactive chat mode."""
    print()
    print("=" * 50)
    print("  Interactive Chat Mode")
    print("=" * 50)
    print(f"  Agent: {args.agent}")
    print("  Commands: 'quit', 'exit', 'clear', 'switch <agent>'")
    print("=" * 50)
    print()

    current_agent_name = args.agent
    agent, deps = await get_agent_and_deps(current_agent_name)
    message_history: list[Any] = []

    while True:
        try:
            user_input = input("You: ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\nGoodbye!")
            break

        if not user_input:
            continue

        if user_input.lower() in ("quit", "exit"):
            print("Goodbye!")
            break

        if user_input.lower() == "clear":
            message_history.clear()
            print("Conversation cleared.\n")
            continue

        if user_input.lower().startswith("switch "):
            new_agent = user_input.split(" ", 1)[1].strip()
            valid_agents = ["router", "research", "analyst", "code", "writer", "support"]
            if new_agent in valid_agents:
                current_agent_name = new_agent
                agent, deps = await get_agent_and_deps(current_agent_name)
                message_history.clear()
                print(f"Switched to {new_agent} agent. History cleared.\n")
            else:
                print(f"Unknown agent. Available: {', '.join(valid_agents)}\n")
            continue

        # Run the agent
        print("\nAssistant: ", end="", flush=True)
        try:
            result = await agent.run(
                user_input,
                deps=deps,
                message_history=message_history,
            )

            response = format_response(current_agent_name, result)
            print(response)

            # Update message history for conversation continuity
            message_history = result.all_messages()

        except Exception as e:
            print(f"Error: {e}")

        print()

    return 0


async def run_query(args: argparse.Namespace) -> int:
    """Run a single query."""
    print(f"\nRunning query with '{args.agent}' agent...")
    print(f"Query: {args.prompt}\n")
    print("-" * 40)

    agent, deps = await get_agent_and_deps(args.agent)

    try:
        result = await agent.run(args.prompt, deps=deps)
        response = format_response(args.agent, result)
        print(response)
    except Exception as e:
        print(f"Error: {e}")
        return 1

    return 0


if __name__ == "__main__":
    sys.exit(main())
