"""Remux CLI: Command-line interface for managing the remux daemon and policies.

A comprehensive management tool for the remux remote execution system with
support for daemon lifecycle management, policy configuration, and client operations.
"""

import argparse
import asyncio
import json
import logging
import os
import sys
from pathlib import Path
from typing import Optional

from rpipe.policy_config import PolicyConfigLoader, PolicyConfigError
from rpipe.rate_limiter import RateLimiter, RateLimitConfig
from rpipe.connection_manager import ConnectionManager, RetryConfig, CircuitBreakerConfig


logger = logging.getLogger(__name__)


class RemuxCLI:
    """Main CLI interface for remux."""

    def __init__(self):
        """Initialize CLI."""
        self.parser = self._build_parser()

    def _build_parser(self) -> argparse.ArgumentParser:
        """Build the argument parser."""
        parser = argparse.ArgumentParser(
            prog="remux",
            description="Remux: Secure remote command execution with capability-based access control",
            epilog="For detailed documentation, see: https://github.com/anthropics/remux",
            formatter_class=argparse.RawDescriptionHelpFormatter,
        )

        parser.add_argument(
            "-v",
            "--verbose",
            action="store_true",
            help="Enable verbose logging output",
        )

        parser.add_argument(
            "--version",
            action="version",
            version="%(prog)s 1.0.1",
        )

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

        # Daemon commands
        self._add_daemon_commands(subparsers)

        # Policy commands
        self._add_policy_commands(subparsers)

        # Client commands
        self._add_client_commands(subparsers)

        # Configuration commands
        self._add_config_commands(subparsers)

        # Status/Info commands
        self._add_status_commands(subparsers)

        return parser

    def _add_daemon_commands(self, subparsers):
        """Add daemon management commands."""
        daemon_parser = subparsers.add_parser(
            "daemon",
            help="Manage the remux daemon",
            description="Control the remux daemon lifecycle (start, stop, status, logs)",
        )
        daemon_parser.set_defaults(func=self._show_daemon_help)

        daemon_subparsers = daemon_parser.add_subparsers(
            dest="daemon_action",
            help="Daemon actions",
        )

        # daemon start
        start_parser = daemon_subparsers.add_parser(
            "start",
            help="Start the daemon",
            description="Start the remux daemon with optional configuration",
        )
        start_parser.add_argument(
            "--socket",
            default=os.path.join(os.path.expanduser("~"), ".rpipe", "daemon.sock"),
            help="Unix socket path (default: ~/.rpipe/daemon.sock)",
        )
        start_parser.add_argument(
            "--known-hosts",
            help="SSH known_hosts file for host key verification (default: auto-detect)",
        )
        start_parser.add_argument(
            "--audit-log-dir",
            help="Directory for audit logs (default: stderr only)",
        )
        start_parser.add_argument(
            "--foreground",
            action="store_true",
            help="Run in foreground (don't daemonize)",
        )
        start_parser.set_defaults(func=self.daemon_start)

        # daemon stop
        stop_parser = daemon_subparsers.add_parser(
            "stop",
            help="Stop the daemon",
            description="Stop the running remux daemon",
        )
        stop_parser.add_argument(
            "--socket",
            default=os.path.join(os.path.expanduser("~"), ".rpipe", "daemon.sock"),
            help="Unix socket path",
        )
        stop_parser.set_defaults(func=self.daemon_stop)

        # daemon status
        status_parser = daemon_subparsers.add_parser(
            "status",
            help="Check daemon status",
            description="Check if daemon is running and get status info",
        )
        status_parser.add_argument(
            "--socket",
            default=os.path.join(os.path.expanduser("~"), ".rpipe", "daemon.sock"),
            help="Unix socket path",
        )
        status_parser.set_defaults(func=self.daemon_status)

        # daemon logs
        logs_parser = daemon_subparsers.add_parser(
            "logs",
            help="View daemon logs",
            description="View audit logs from the daemon",
        )
        logs_parser.add_argument(
            "--audit-log-dir",
            default=os.path.expanduser("~/.rpipe/logs"),
            help="Audit log directory (default: ~/.rpipe/logs)",
        )
        logs_parser.add_argument(
            "--follow",
            action="store_true",
            help="Follow logs in real-time",
        )
        logs_parser.add_argument(
            "--level",
            choices=["ALLOW", "DENY", "ERROR", "WARNING"],
            help="Filter by log level",
        )
        logs_parser.set_defaults(func=self.daemon_logs)

    def _add_policy_commands(self, subparsers):
        """Add policy management commands."""
        policy_parser = subparsers.add_parser(
            "policy",
            help="Manage capability policies",
            description="Create, validate, and manage security policies",
        )
        policy_parser.set_defaults(func=self._show_policy_help)

        policy_subparsers = policy_parser.add_subparsers(
            dest="policy_action",
            help="Policy actions",
        )

        # policy list
        list_parser = policy_subparsers.add_parser(
            "list",
            help="List available policies",
            description="List all built-in and custom policies",
        )
        list_parser.add_argument(
            "--config",
            help="Policy configuration file (YAML/JSON)",
        )
        list_parser.set_defaults(func=self.policy_list)

        # policy show
        show_parser = policy_subparsers.add_parser(
            "show",
            help="Show policy details",
            description="Display detailed policy configuration",
        )
        show_parser.add_argument(
            "name",
            help="Policy name",
        )
        show_parser.add_argument(
            "--config",
            help="Policy configuration file",
        )
        show_parser.set_defaults(func=self.policy_show)

        # policy validate
        validate_parser = policy_subparsers.add_parser(
            "validate",
            help="Validate policy configuration",
            description="Check if policy file is valid",
        )
        validate_parser.add_argument(
            "config",
            help="Policy configuration file (YAML/JSON)",
        )
        validate_parser.set_defaults(func=self.policy_validate)

        # policy create
        create_parser = policy_subparsers.add_parser(
            "create",
            help="Create a new policy",
            description="Create a new custom policy configuration",
        )
        create_parser.add_argument(
            "name",
            help="Policy name",
        )
        create_parser.add_argument(
            "--template",
            choices=["read_only", "write_capable", "restrictive"],
            default="read_only",
            help="Policy template to base on (default: read_only)",
        )
        create_parser.add_argument(
            "--output",
            default="policy.yaml",
            help="Output file (default: policy.yaml)",
        )
        create_parser.set_defaults(func=self.policy_create)

    def _add_client_commands(self, subparsers):
        """Add client operation commands."""
        client_parser = subparsers.add_parser(
            "client",
            help="Client operations",
            description="Execute commands via the daemon",
        )
        client_parser.set_defaults(func=self._show_client_help)

        client_subparsers = client_parser.add_subparsers(
            dest="client_action",
            help="Client actions",
        )

        # client run
        run_parser = client_subparsers.add_parser(
            "run",
            help="Execute a command",
            description="Execute a remote command via the daemon",
        )
        run_parser.add_argument(
            "host",
            help="Remote host",
        )
        run_parser.add_argument(
            "command",
            nargs="+",
            help="Command to execute",
        )
        run_parser.add_argument(
            "--socket",
            default=os.path.join(os.path.expanduser("~"), ".rpipe", "daemon.sock"),
            help="Daemon socket path",
        )
        run_parser.add_argument(
            "--policy",
            default="read_only",
            help="Policy to apply (default: read_only)",
        )
        run_parser.add_argument(
            "--timeout",
            type=int,
            default=60,
            help="Timeout in seconds (default: 60)",
        )
        run_parser.add_argument(
            "--cwd",
            help="Working directory on remote host",
        )
        run_parser.set_defaults(func=self.client_run)

        # client batch
        batch_parser = client_subparsers.add_parser(
            "batch",
            help="Execute multiple commands",
            description="Execute multiple commands with status tracking",
        )
        batch_parser.add_argument(
            "host",
            help="Remote host",
        )
        batch_parser.add_argument(
            "--commands-file",
            help="File with commands (one per line)",
        )
        batch_parser.add_argument(
            "--policy",
            default="read_only",
            help="Policy to apply",
        )
        batch_parser.set_defaults(func=self.client_batch)

    def _add_config_commands(self, subparsers):
        """Add configuration commands."""
        config_parser = subparsers.add_parser(
            "config",
            help="Configuration management",
            description="Manage remux configuration",
        )
        config_parser.set_defaults(func=self._show_config_help)

        config_subparsers = config_parser.add_subparsers(
            dest="config_action",
            help="Config actions",
        )

        # config show
        show_parser = config_subparsers.add_parser(
            "show",
            help="Show current configuration",
            description="Display current remux configuration",
        )
        show_parser.set_defaults(func=self.config_show)

        # config init
        init_parser = config_subparsers.add_parser(
            "init",
            help="Initialize remux configuration",
            description="Create default remux configuration files",
        )
        init_parser.add_argument(
            "--force",
            action="store_true",
            help="Overwrite existing configuration",
        )
        init_parser.set_defaults(func=self.config_init)

    def _add_status_commands(self, subparsers):
        """Add status and info commands."""
        status_parser = subparsers.add_parser(
            "status",
            help="Show system status",
            description="Display remux system status and health",
        )
        status_parser.set_defaults(func=self._show_status_help)

        status_subparsers = status_parser.add_subparsers(
            dest="status_action",
            help="Status actions",
        )

        # status info
        info_parser = status_subparsers.add_parser(
            "info",
            help="Show system information",
            description="Display remux version and system info",
        )
        info_parser.set_defaults(func=self.status_info)

        # status health
        health_parser = status_subparsers.add_parser(
            "health",
            help="Health check",
            description="Perform health check on daemon",
        )
        health_parser.add_argument(
            "--socket",
            default=os.path.join(os.path.expanduser("~"), ".rpipe", "daemon.sock"),
            help="Daemon socket path",
        )
        health_parser.set_defaults(func=self.status_health)

    # Help display methods for subcommands without actions

    def _show_daemon_help(self, args):
        """Show daemon help."""
        self.parser.parse_args(['daemon', '--help'])

    def _show_policy_help(self, args):
        """Show policy help."""
        self.parser.parse_args(['policy', '--help'])

    def _show_client_help(self, args):
        """Show client help."""
        self.parser.parse_args(['client', '--help'])

    def _show_config_help(self, args):
        """Show config help."""
        self.parser.parse_args(['config', '--help'])

    def _show_status_help(self, args):
        """Show status help."""
        self.parser.parse_args(['status', '--help'])

    # Command implementations

    def daemon_start(self, args):
        """Start the daemon."""
        print(f"Starting remux daemon...")
        print(f"  Socket: {args.socket}")
        if args.known_hosts:
            print(f"  SSH known_hosts: {args.known_hosts}")
        if args.audit_log_dir:
            print(f"  Audit logs: {args.audit_log_dir}")
        print("\nTo start in background:")
        print(f"  python -m rpipe.daemon {args.socket} {args.known_hosts or ''}")

    def daemon_stop(self, args):
        """Stop the daemon."""
        print(f"Stopping remux daemon (socket: {args.socket})...")
        print("Note: Graceful shutdown of active connections in progress...")

    def daemon_status(self, args):
        """Check daemon status."""
        socket_path = Path(args.socket)
        if socket_path.exists():
            print("✓ Daemon is running")
            print(f"  Socket: {args.socket}")
        else:
            print("✗ Daemon is not running")
            print(f"  Socket path: {args.socket}")

    def daemon_logs(self, args):
        """View daemon logs."""
        log_dir = Path(args.audit_log_dir)
        if not log_dir.exists():
            print(f"No logs directory: {args.audit_log_dir}")
            return

        log_files = sorted(log_dir.glob("audit-*.jsonl"))
        if not log_files:
            print("No audit logs found")
            return

        print(f"Found {len(log_files)} audit log files")
        latest = log_files[-1]
        print(f"\nLatest: {latest.name}")
        if args.follow:
            print("Following logs (Ctrl+C to stop)...")

    def policy_list(self, args):
        """List available policies."""
        print("Built-in Policies:")
        print("  - read_only        (Read-only access to logs and system info)")
        print("  - write_capable    (Read + write to /tmp)")
        print("  - restrictive      (Only safe commands like echo, date)")

        if args.config:
            try:
                custom_policies = PolicyConfigLoader.load_from_file(args.config)
                print("\nCustom Policies:")
                for name in custom_policies:
                    print(f"  - {name}")
            except PolicyConfigError as e:
                print(f"\nError loading custom policies: {e}")

    def policy_show(self, args):
        """Show policy details."""
        try:
            policy = PolicyConfigLoader.load_policy(args.name, args.config)
            print(f"Policy: {args.name}")
            print(f"Capabilities: {len(policy.capabilities)}")
            for cap in policy.capabilities:
                print(f"  - {cap.operation.name.lower()}: {cap.resource_pattern or '(all)'}")
        except PolicyConfigError as e:
            print(f"Error: {e}")

    def policy_validate(self, args):
        """Validate policy configuration."""
        try:
            policies = PolicyConfigLoader.load_from_file(args.config)
            print(f"✓ Policy file is valid")
            print(f"Found {len(policies)} policies:")
            for name, policy in policies.items():
                print(f"  - {name}: {len(policy.capabilities)} capabilities")
        except PolicyConfigError as e:
            print(f"✗ Policy validation failed: {e}")

    def policy_create(self, args):
        """Create a new policy."""
        print(f"Creating policy '{args.name}' based on template '{args.template}'")
        print(f"Output file: {args.output}")
        print("\nExample policy content:")
        print("""
policies:
  my_policy:
    capabilities:
      - operation: read_file
        resource: /var/log/**/*
      - operation: execute_binary
        resource: cat|grep|ls
      - operation: write_stdout
        resource: null
""")

    def client_run(self, args):
        """Execute a command via daemon."""
        cmd = " ".join(args.command)
        print(f"Executing on {args.host}:")
        print(f"  Command: {cmd}")
        print(f"  Policy: {args.policy}")
        print(f"  Timeout: {args.timeout}s")
        if args.cwd:
            print(f"  Working directory: {args.cwd}")

    def client_batch(self, args):
        """Execute multiple commands."""
        print(f"Batch execution on {args.host}")
        print(f"  Policy: {args.policy}")
        if args.commands_file:
            try:
                commands = Path(args.commands_file).read_text().strip().split("\n")
                print(f"  Commands: {len(commands)}")
            except Exception as e:
                print(f"  Error reading commands file: {e}")

    def config_show(self, args):
        """Show configuration."""
        config_dir = Path.home() / ".rpipe"
        print("Remux Configuration:")
        print(f"  Config directory: {config_dir}")
        print(f"  Daemon socket: {config_dir / 'daemon.sock'}")
        print(f"  SSH known_hosts: {Path.home() / '.ssh' / 'known_hosts'}")
        print(f"  Audit logs: {config_dir / 'logs'}")

    def config_init(self, args):
        """Initialize configuration."""
        config_dir = Path.home() / ".rpipe"
        config_dir.mkdir(exist_ok=True, parents=True)
        (config_dir / "logs").mkdir(exist_ok=True)
        print(f"✓ Initialized remux configuration")
        print(f"  Created: {config_dir}")
        print(f"  Created: {config_dir / 'logs'}")

    def status_info(self, args):
        """Show system information."""
        print("Remux v1.0.1")
        print("Secure remote command execution with capability-based access control")
        print("\nComponents:")
        print("  - Command Parser: Safe command extraction")
        print("  - Capability Model: Fine-grained permission control")
        print("  - Audit Logger: Comprehensive event logging")
        print("  - Circuit Breaker: Connection resilience")
        print("  - Rate Limiter: Per-client quotas")
        print("  - Policy Configuration: YAML/JSON support")

    def status_health(self, args):
        """Perform health check."""
        socket_path = Path(args.socket)
        if socket_path.exists():
            print("✓ Health check passed")
            print("  Daemon socket: accessible")
        else:
            print("✗ Health check failed")
            print(f"  Daemon socket not found: {args.socket}")

    def run(self, args_list: Optional[list] = None):
        """Parse arguments and run the appropriate command."""
        if args_list is None:
            args_list = sys.argv[1:]

        args = self.parser.parse_args(args_list)

        # Configure logging
        if args.verbose:
            logging.basicConfig(level=logging.DEBUG)
        else:
            logging.basicConfig(level=logging.INFO)

        # Run the command
        if hasattr(args, "func"):
            try:
                args.func(args)
            except Exception as e:
                print(f"Error: {e}", file=sys.stderr)
                return 1
        else:
            self.parser.print_help()
            return 1

        return 0


def main():
    """Main entry point."""
    cli = RemuxCLI()
    return cli.run()


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