"""Main entry point for PentestAgent."""

import argparse
import asyncio

from ..config.constants import AGENT_MAX_ITERATIONS, DEFAULT_MODEL
from .cli import run_cli
from .tui import run_tui


def parse_arguments():
    """Parse command line arguments."""
    parser = argparse.ArgumentParser(
        description="PentestAgent - AI Penetration Testing",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  pentestagent tui                              Launch TUI
  pentestagent tui -t 192.168.1.1               Launch TUI with target
  pentestagent run -t localhost --task "scan"   Headless run
  pentestagent tools list                       List available tools
  pentestagent mcp list                         List MCP servers
        """,
    )

    parser.add_argument("--version", action="version", version="PentestAgent 0.2.0")

    # Subcommands
    subparsers = parser.add_subparsers(dest="command", help="Commands")

    # Common arguments for runtime modes
    runtime_parent = argparse.ArgumentParser(add_help=False)
    runtime_parent.add_argument("--target", "-t", help="Target (IP, hostname, or URL)")
    runtime_parent.add_argument(
        "--model",
        "-m",
        default=DEFAULT_MODEL,
        help="LLM model (set PENTESTAGENT_MODEL in .env)",
    )
    runtime_parent.add_argument(
        "--docker",
        "-d",
        action="store_true",
        help="Run tools inside Docker container (requires Docker)",
    )
    runtime_parent.add_argument(
        "--playbook",
        "-p",
        help="Playbook to execute (e.g., thp3_web)",
    )

    # TUI subcommand
    subparsers.add_parser(
        "tui", parents=[runtime_parent], help="Launch TUI (Interactive Mode)"
    )

    # Run subcommand (Headless)
    run_parser = subparsers.add_parser(
        "run", parents=[runtime_parent], help="Run in headless mode"
    )
    run_parser.add_argument("task", nargs="*", help="Task to run")
    run_parser.add_argument(
        "--report",
        "-r",
        nargs="?",
        const="auto",
        help=(
            "Generate report. "
            "If used without value, auto-generates path under loot/reports/. "
            "If omitted, no report is generated."
        ),
    )
    run_parser.add_argument(
        "--max-loops",
        type=int,
        default=AGENT_MAX_ITERATIONS,
        help=f"Max agent loops before stopping (default: {AGENT_MAX_ITERATIONS})",
    )

    # Tools subcommand
    tools_parser = subparsers.add_parser("tools", help="Manage tools")
    tools_subparsers = tools_parser.add_subparsers(
        dest="tools_command", help="Tool commands"
    )

    # tools list
    tools_subparsers.add_parser("list", help="List all available tools")

    # tools info
    tools_info = tools_subparsers.add_parser("info", help="Show tool details")
    tools_info.add_argument("name", help="Tool name")

    # tools env
    tools_subparsers.add_parser("env", help="Show detected CLI tools in environment")

    # MCP subcommand
    mcp_parser = subparsers.add_parser("mcp", help="Manage MCP servers")
    mcp_subparsers = mcp_parser.add_subparsers(dest="mcp_command", help="MCP commands")

    # mcp list
    mcp_subparsers.add_parser("list", help="List configured MCP servers")

    # mcp add
    mcp_add = mcp_subparsers.add_parser("add", help="Add an MCP server")
    mcp_add.add_argument("name", help="Server name")
    mcp_add.add_argument("command", help="Command to run (e.g., npx)")
    mcp_add.add_argument("args", nargs="*", help="Command arguments")
    mcp_add.add_argument("--description", default="", help="Server description")

    # mcp remove
    mcp_remove = mcp_subparsers.add_parser("remove", help="Remove an MCP server")
    mcp_remove.add_argument("name", help="Server name to remove")

    # mcp disable
    mcp_disable = mcp_subparsers.add_parser(
        "disable", help="Disable an MCP server (update config)"
    )
    mcp_disable.add_argument("name", help="Server name to disable")

    # mcp enable
    mcp_enable = mcp_subparsers.add_parser(
        "enable", help="Enable an MCP server (update config)"
    )
    mcp_enable.add_argument("name", help="Server name to enable")

    # mcp test
    mcp_test = mcp_subparsers.add_parser("test", help="Test MCP server connection")
    mcp_test.add_argument("name", help="Server name to test")

    return parser, parser.parse_args()


def handle_tools_command(args: argparse.Namespace):
    """Handle tools subcommand."""
    from rich.console import Console
    from rich.table import Table

    from ..tools import get_all_tools, get_tool

    console = Console()

    if args.tools_command == "list":
        tools = get_all_tools()

        if not tools:
            console.print("[yellow]No tools found[/]")
            return

        table = Table(title="Available Tools")
        table.add_column("Name", style="cyan")
        table.add_column("Category", style="green")
        table.add_column("Description")

        for tool in sorted(tools, key=lambda t: t.name):
            desc = (
                tool.description[:50] + "..."
                if len(tool.description) > 50
                else tool.description
            )
            table.add_row(tool.name, tool.category, desc)

        console.print(table)
        console.print(f"\nTotal: {len(tools)} tools")

    elif args.tools_command == "info":
        tool = get_tool(args.name)
        if not tool:
            console.print(f"[red]Tool not found: {args.name}[/]")
            return

        console.print(f"\n[bold cyan]{tool.name}[/]")
        console.print(f"[dim]Category:[/] {tool.category}")
        console.print(f"\n{tool.description}")

        if tool.schema.properties:
            console.print("\n[bold]Parameters:[/]")
            for name, props in tool.schema.properties.items():
                required = (
                    "required" if name in (tool.schema.required or []) else "optional"
                )
                ptype = props.get("type", "any")
                desc = props.get("description", "")
                console.print(f"  [cyan]{name}[/] ({ptype}, {required}): {desc}")

    elif args.tools_command == "env":
        from ..runtime.runtime import detect_environment

        env = detect_environment()

        console.print("\n[bold]Environment:[/]")
        console.print(f"  OS: {env.os} ({env.os_version})")
        console.print(f"  Architecture: {env.architecture}")
        console.print(f"  Shell: {env.shell}")

        if env.available_tools:
            console.print(
                f"\n[bold]Detected CLI Tools ({len(env.available_tools)}):[/]"
            )

            # Group by category
            by_category = {}
            for tool_info in env.available_tools:
                if tool_info.category not in by_category:
                    by_category[tool_info.category] = []
                by_category[tool_info.category].append(tool_info)

            for category in sorted(by_category.keys()):
                tools_in_cat = by_category[category]
                console.print(f"\n[bold cyan]{category}[/] ({len(tools_in_cat)}):")
                for tool_info in sorted(tools_in_cat, key=lambda t: t.name):
                    console.print(f"  • {tool_info.name}")
        else:
            console.print("\n[yellow]No CLI tools detected[/]")
            console.print(
                "\n[dim]Tip: Install tools like nmap, curl, git to expand capabilities[/]"
            )

    else:
        console.print("[yellow]Use 'pentestagent tools --help' for commands[/]")


def handle_mcp_command(args: argparse.Namespace):
    """Handle MCP subcommand."""
    from rich.console import Console
    from rich.table import Table

    from ..mcp.manager import MCPManager

    console = Console()
    manager = MCPManager()

    if args.mcp_command == "list":
        servers = manager.list_configured_servers()

        if not servers:
            console.print("[yellow]No MCP servers configured[/]")
            console.print(
                "\nAdd a server with: pentestagent mcp add <name> <command> <args...>"
            )
            return

        table = Table(title="Configured MCP Servers")
        table.add_column("Name", style="cyan")
        table.add_column("Command", style="green")
        table.add_column("Args")
        table.add_column("Connected", style="yellow")

        for server in servers:
            args_str = " ".join(server["args"][:3])
            if len(server["args"]) > 3:
                args_str += "..."
            connected = "+" if server.get("connected") else "-"
            table.add_row(server["name"], server["command"], args_str, connected)

        console.print(table)
        console.print(f"\nConfig file: {manager.config_path}")

    elif args.mcp_command == "add":
        manager.add_server(
            name=args.name,
            command=args.command,
            args=args.args or [],
            description=args.description,
        )
        console.print(f"[green]Added MCP server: {args.name}[/]")
        console.print(f"  Command: {args.command} {' '.join(args.args or [])}")

    elif args.mcp_command == "remove":
        if manager.remove_server(args.name):
            console.print(f"[yellow]Removed MCP server: {args.name}[/]")
        else:
            console.print(f"[red]Server not found: {args.name}[/]")

    elif args.mcp_command == "disable":
        if manager.set_enabled(args.name, False):
            console.print(f"[yellow]Disabled MCP server in config: {args.name}[/]")
        else:
            console.print(f"[red]Server not found: {args.name}[/]")

    elif args.mcp_command == "enable":
        if manager.set_enabled(args.name, True):
            console.print(f"[green]Enabled MCP server in config: {args.name}[/]")
        else:
            console.print(f"[red]Server not found: {args.name}[/]")

    elif args.mcp_command == "test":
        console.print(f"[bold]Testing MCP server: {args.name}[/]\n")

        async def test_server():
            server = await manager.connect_server(args.name)
            if server and server.connected:
                console.print("[green]+ Connected successfully![/]")
                console.print(f"\n[bold]Available tools ({len(server.tools)}):[/]")
                for tool in server.tools:
                    desc = tool.get("description", "No description")[:60]
                    console.print(f"  [cyan]{tool['name']}[/]: {desc}")
                await manager.disconnect_all()
            else:
                console.print("[red]x Failed to connect[/]")

        asyncio.run(test_server())

    else:
        console.print("[yellow]Use 'pentestagent mcp --help' for available commands[/]")


def main():
    """Main entry point."""
    parser, args = parse_arguments()

    # Handle subcommands
    if args.command == "tools":
        handle_tools_command(args)
        return

    if args.command == "mcp":
        handle_mcp_command(args)
        return

    if args.command == "run":
        # Check model configuration
        if not args.model:
            print("Error: No model configured.")
            print("Set PENTESTAGENT_MODEL in .env file or use --model flag.")
            print(
                "Example: PENTESTAGENT_MODEL=gpt-5 or PENTESTAGENT_MODEL=claude-sonnet-4-20250514"
            )
            return

        if not args.target:
            print("Error: --target is required for run mode")
            return

        # Handle playbook or task
        task_description = ""
        mode = "agent"
        if args.playbook:
            from ..playbooks import get_playbook

            try:
                playbook = get_playbook(args.playbook)
                task_description = playbook.get_task()
                mode = getattr(playbook, "mode", "agent")

                # Use playbook's max_loops if defined
                if hasattr(playbook, "max_loops"):
                    args.max_loops = playbook.max_loops

                print(f"Loaded playbook: {playbook.name}")
                print(f"Description: {playbook.description}")
                print(f"Mode: {mode}")
            except ValueError as e:
                print(f"Error: {e}")
                return
        elif args.task:
            task_description = " ".join(args.task)
        else:
            print("Error: Either task (positional) or --playbook is required")
            return

        try:
            asyncio.run(
                run_cli(
                    target=args.target,
                    model=args.model,
                    task=task_description,
                    report=args.report,
                    max_loops=args.max_loops,
                    use_docker=args.docker,
                    mode=mode,
                )
            )
        except KeyboardInterrupt:
            print("\n[!] Interrupted by user.")
        return

    if args.command == "tui":
        # Check model configuration
        if not args.model:
            print("Error: No model configured.")
            print("Set PENTESTAGENT_MODEL in .env file or use --model flag.")
            print(
                "Example: PENTESTAGENT_MODEL=gpt-5 or PENTESTAGENT_MODEL=claude-sonnet-4-20250514"
            )
            return

        run_tui(target=args.target, model=args.model, use_docker=args.docker)
        return

    # If no command provided, default to TUI
    if args.command is None:
        run_tui(target=None, model=DEFAULT_MODEL, use_docker=False)
        return


if __name__ == "__main__":
    main()
