"""
Main CLI implementation for FHEnom AI.
"""

import click
import logging
import sys
import json
import yaml
from pathlib import Path
from typing import Optional
from rich.console import Console
from rich.table import Table
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.prompt import Confirm
from rich import print as rprint

from .config import FHEnomConfig
from .admin_api import AdminAPI
from .sftp import SFTPClient
from .exceptions import FHEnomError
from .client import FHEnomClient

# Get version
try:
    from importlib.metadata import version
    __version__ = version("fhenomai")
except Exception:
    __version__ = "1.0.0"

# Setup console with no width limit to prevent truncation
console = Console(width=200, soft_wrap=True)

# Setup logging
logging.basicConfig(
    level=logging.WARNING,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


# Context object for passing config between commands
class Context:
    def __init__(self):
        self.config: Optional[FHEnomConfig] = None
        self.verbose: bool = False
        self.quiet: bool = False


pass_context = click.make_pass_decorator(Context, ensure=True)


@click.group()
@click.option('--config', '-c', type=click.Path(exists=True), help='Configuration file path')
@click.option('--verbose', '-v', is_flag=True, help='Enable verbose output')
@click.option('--quiet', '-q', is_flag=True, help='Suppress non-essential output')
@click.version_option(version=__version__)
@pass_context
def cli(ctx: Context, config: Optional[str], verbose: bool, quiet: bool):
    """FHEnom AI Command Line Interface - Manage encrypted AI models and datasets."""
    ctx.verbose = verbose
    ctx.quiet = quiet
    
    if verbose:
        logging.getLogger().setLevel(logging.DEBUG)
    elif quiet:
        logging.getLogger().setLevel(logging.ERROR)
    
    # Load config
    try:
        if config:
            ctx.config = FHEnomConfig.from_file(config)
        else:
            ctx.config = FHEnomConfig.from_file()
    except FileNotFoundError as e:
        if config:
            # User specified a config file but it doesn't exist
            console.print(f"[red]Error:[/red] {e}")
            sys.exit(1)
        # No config specified and no default found - that's okay for init command
        ctx.config = None


# ============================================================================
# CONFIG COMMANDS
# ============================================================================

@cli.group(name='config')
def config_cmd():
    """Configuration management commands."""
    pass


@config_cmd.command()
@click.option('--output', '-o', type=click.Path(), help='Output file path')
@click.option('--tee-ip', '--admin-host', 'admin_host', help='TEE/Admin API host IP')
@click.option('--admin-api-port', '--admin-port', 'admin_port', type=int, help='Admin API port')
@click.option('--user-host', help='User API host')
@click.option('--user-port', type=int, help='User API port')
@click.option('--sftp-host', help='SFTP host')
@click.option('--sftp-port', type=int, help='SFTP port')
@click.option('--sftp-username', help='SFTP username')
@click.option('--sftp-password', help='SFTP password')
@click.option('--workspace', type=click.Path(), help='Local workspace directory path')
@click.option('--timeout', type=int, help='Request timeout in seconds')
@click.option('--max-retries', type=int, help='Maximum number of retries')
@pass_context
def init(ctx: Context, output: Optional[str], admin_host: Optional[str], 
         admin_port: Optional[int], user_host: Optional[str], user_port: Optional[int],
         sftp_host: Optional[str], sftp_port: Optional[int], sftp_username: Optional[str],
         sftp_password: Optional[str], workspace: Optional[str], timeout: Optional[int], max_retries: Optional[int]):
    """Initialize a new configuration file."""
    if output is None:
        output = str(Path.home() / ".fhenomai" / "config.yaml")
    
    output_path = Path(output)
    
    # Check if file already exists
    if output_path.exists():
        if not click.confirm(f"Config file already exists at {output_path}. Overwrite?"):
            console.print("[yellow]Cancelled[/yellow]")
            return
    
    # Create default config
    output_path.parent.mkdir(parents=True, exist_ok=True)
    
    # Build config with provided values or defaults
    # If tee-ip (admin_host) is provided, use it as default for user_host and sftp_host
    default_host = admin_host or '192.168.1.100'
    
    default_config = {
        'admin_host': default_host,
        'admin_port': admin_port or 9099,
        'user_host': user_host or default_host,
        'user_port': user_port or 9999,
        'sftp_host': sftp_host or default_host,
        'sftp_port': sftp_port or 22,
        'sftp_username': sftp_username or 'admin',
        'sftp_password': sftp_password or 'your-password',
        'workspace': workspace or str(Path.home() / 'fhenomai_workspace'),
        'timeout': timeout or 30,
        'max_retries': max_retries or 3
    }
    
    with open(output_path, 'w') as f:
        yaml.dump(default_config, f, default_flow_style=False)
    
    console.print(f"[green]✓[/green] Created config file: {output_path}")
    if not any([admin_host, admin_port, user_host, user_port, sftp_host, sftp_port, sftp_username, sftp_password]):
        console.print("\n[yellow]Please edit the file to add your credentials:[/yellow]")
        console.print(f"  {output_path}")


@config_cmd.command()
@pass_context
def show(ctx: Context):
    """Show current configuration."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    console.print("\n[bold]Current Configuration:[/bold]\n")
    
    table = Table(show_header=False, box=None)
    table.add_column("Key", style="cyan", no_wrap=True)
    table.add_column("Value", no_wrap=True, overflow="fold")
    
    table.add_row("Admin URL", ctx.config.admin_url)
    table.add_row("User URL", ctx.config.user_url)
    table.add_row("SFTP Host", f"{ctx.config.sftp_host}:{ctx.config.sftp_port}")
    table.add_row("SFTP User", ctx.config.sftp_username)
    table.add_row("Workspace", getattr(ctx.config, 'workspace', 'Not set'))
    table.add_row("Timeout", f"{ctx.config.timeout}s")
    table.add_row("Max Retries", str(ctx.config.max_retries))
    
    console.print(table)
    console.print()


@config_cmd.command()
@click.argument('key')
@pass_context
def get(ctx: Context, key: str):
    """Get a specific configuration value (machine-readable output)."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found", file=sys.stderr)
        sys.exit(1)
    
    # Map of user-friendly keys to config attributes
    key_map = {
        'admin-url': 'admin_url',
        'admin-host': 'admin_host',
        'admin-port': 'admin_port',
        'user-url': 'user_url',
        'user-host': 'user_host',
        'user-port': 'user_port',
        'sftp-host': 'sftp_host',
        'sftp-port': 'sftp_port',
        'sftp-username': 'sftp_username',
        'workspace': 'workspace',
        'timeout': 'timeout',
        'max-retries': 'max_retries',
    }
    
    # Normalize key (allow both - and _)
    normalized_key = key.lower().replace('_', '-')
    
    if normalized_key not in key_map:
        console.print(f"[red]Error:[/red] Unknown key '{key}'", file=sys.stderr)
        console.print(f"Available keys: {', '.join(sorted(key_map.keys()))}", file=sys.stderr)
        sys.exit(1)
    
    attr_name = key_map[normalized_key]
    value = getattr(ctx.config, attr_name, None)
    
    if value is None:
        console.print(f"[red]Error:[/red] Key '{key}' not set", file=sys.stderr)
        sys.exit(1)
    
    # Print raw value without any formatting (stdout only, no rich formatting)
    print(value)


@config_cmd.command()
@pass_context
def validate(ctx: Context):
    """Validate configuration file."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    console.print("[green]✓[/green] Configuration is valid")
    
    # Try to connect to services
    console.print("\nTesting connectivity...")
    
    # Test Admin API
    try:
        client = FHEnomClient(ctx.config)
        client.list_models()
        console.print("  [green]✓[/green] Admin API")
    except Exception as e:
        console.print(f"  [red]✗[/red] Admin API: {e}")
    
    # Test SFTP
    try:
        sftp = SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path,
            auto_connect=True
        )
        sftp.disconnect()
        console.print("  [green]✓[/green] SFTP")
    except Exception as e:
        console.print(f"  [red]✗[/red] SFTP: {e}")


# ============================================================================
# HEALTH CHECK COMMANDS
# ============================================================================

@cli.group()
def health():
    """Health check commands."""
    pass


@health.command()
@pass_context
def check(ctx: Context):
    """Check connectivity to all services."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    console.print("\n[bold]Health Check[/bold]\n")
    
    all_ok = True
    
    # Admin API
    console.print("Testing Admin API...", end=" ")
    try:
        client = FHEnomClient(ctx.config)
        models = client.list_models()
        console.print(f"[green]✓[/green] ({len(models)} models)")
    except Exception as e:
        console.print(f"[red]✗[/red] {e}")
        all_ok = False
    
    # SFTP
    console.print("Testing SFTP...", end=" ")
    try:
        with SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path
        ):
            pass
        console.print("[green]✓[/green]")
    except Exception as e:
        console.print(f"[red]✗[/red] {e}")
        all_ok = False
    
    console.print()
    
    if all_ok:
        console.print("[green]All systems operational[/green]")
        sys.exit(0)
    else:
        console.print("[red]Some systems failed[/red]")
        sys.exit(1)


@health.command()
@pass_context
def admin(ctx: Context):
    """Test Admin API connectivity."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        models = client.list_models()
        console.print(f"[green]✓[/green] Admin API is reachable ({len(models)} models configured)")
    except Exception as e:
        console.print(f"[red]✗[/red] Admin API failed: {e}")
        sys.exit(1)


@health.command()
@pass_context
def sftp(ctx: Context):
    """Test SFTP connectivity."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        with SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path
        ):
            pass
        console.print("[green]✓[/green] SFTP connection successful")
    except Exception as e:
        console.print(f"[red]✗[/red] SFTP failed: {e}")
        sys.exit(1)


@health.command()
@pass_context
def live(ctx: Context):
    """Check service liveness (lightweight check, no authentication required)."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        result = client.admin.health_live()
        
        if result.get("status") == "alive":
            console.print("[green]✓[/green] Service is alive")
            console.print(f"Status: {result['status']}")
        else:
            console.print(f"[yellow]⚠[/yellow] Unexpected response: {result}")
    except Exception as e:
        console.print(f"[red]✗[/red] Liveness check failed: {e}")
        sys.exit(1)


@health.command()
@pass_context
def ready(ctx: Context):
    """Check system readiness and subsystem status."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        result = client.admin.health_ready()
        
        console.print("\n[bold]System Readiness[/bold]\n")
        
        # Create table
        table = Table(show_header=True, header_style="bold cyan")
        table.add_column("Subsystem", style="white", no_wrap=True)
        table.add_column("Status", style="white")
        
        all_ready = True
        for subsystem, status in result.items():
            if status.lower() in ["available", "up", "ready"]:
                status_display = f"[green]{status}[/green]"
            elif status.lower() in ["unavailable", "down", "not ready"]:
                status_display = f"[red]{status}[/red]"
                all_ready = False
            else:
                status_display = f"[yellow]{status}[/yellow]"
            
            table.add_row(subsystem, status_display)
        
        console.print(table)
        console.print()
        
        if all_ready:
            console.print("[green]✓[/green] All subsystems ready")
        else:
            console.print("[yellow]⚠[/yellow] Some subsystems not ready")
            sys.exit(1)
            
    except Exception as e:
        console.print(f"[red]✗[/red] Readiness check failed: {e}")
        sys.exit(1)


@health.command()
@click.option('--model-id', '-m', help='Filter metrics for specific model')
@click.option('--json-output', '-j', is_flag=True, help='Output raw JSON')
@pass_context
def status(ctx: Context, model_id: Optional[str], json_output: bool):
    """Get performance metrics and system status."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        result = client.admin.health_status()
        
        if json_output:
            console.print(json.dumps(result, indent=2))
            return
        
        console.print("\n[bold]Performance Metrics[/bold]\n")
        
        # Show aggregate metrics
        if 'aggregate' in result:
            agg = result['aggregate']
            console.print("[bold cyan]Aggregate Metrics[/bold cyan]")
            console.print(f"  Latency: {agg.get('latency', 'N/A')}")
            console.print(f"  Tokens/sec: {agg.get('tokens_per_second', 'N/A')}")
            console.print(f"  Total requests: {agg.get('total_requests', 'N/A')}")
            console.print(f"  Last seen: {agg.get('last_seen', 'N/A')}")
            console.print()
        
        # Show per-model metrics
        if 'per_model' in result and result['per_model']:
            console.print("[bold cyan]Per-Model Metrics[/bold cyan]\n")
            
            table = Table(show_header=True, header_style="bold cyan")
            table.add_column("Model ID", style="white", no_wrap=False)
            table.add_column("Latency", justify="right")
            table.add_column("Tokens/sec", justify="right")
            table.add_column("Requests", justify="right")
            table.add_column("Last Seen", style="dim")
            
            for mid, metrics in result['per_model'].items():
                # Filter by model_id if specified
                if model_id and model_id not in mid:
                    continue
                    
                table.add_row(
                    mid,
                    f"{metrics.get('latency', 'N/A')}",
                    f"{metrics.get('tokens_per_second', 'N/A')}",
                    f"{metrics.get('total_requests', 'N/A')}",
                    f"{metrics.get('last_seen', 'N/A')}"
                )
            
            console.print(table)
        else:
            console.print("[dim]No per-model metrics available[/dim]")
        
        # Show timestamp
        if 'timestamp' in result:
            console.print(f"\n[dim]Snapshot: {result['timestamp']}[/dim]")
        
        console.print()
        
    except Exception as e:
        console.print(f"[red]✗[/red] Status check failed: {e}")
        sys.exit(1)


# ============================================================================
# TEST COMMANDS (Alias for health commands)
# ============================================================================

@cli.group()
def test():
    """Test connectivity and functionality."""
    pass


@test.command(name='connection')
@pass_context
def test_connection(ctx: Context):
    """Test connection to all services."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found. Run 'fhenomai config init' first.")
        sys.exit(1)
    
    console.print("\n[bold]Testing Connections[/bold]\n")
    all_ok = True
    
    # Test Admin API
    console.print("Testing Admin API...", end=" ")
    try:
        client = FHEnomClient(ctx.config)
        models = client.list_models()
        console.print(f"[green]✓[/green] Connected ({len(models)} models)")
    except Exception as e:
        console.print(f"[red]✗[/red] {str(e)[:50]}")
        all_ok = False
    
    # Test SFTP
    console.print("Testing SFTP...", end=" ")
    try:
        sftp = SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path,
            auto_connect=True
        )
        sftp.disconnect()
        console.print("[green]✓[/green] Connected")
    except Exception as e:
        console.print(f"[red]✗[/red] {str(e)[:50]}")
        all_ok = False
    
    console.print()
    
    if all_ok:
        console.print("[green]✓ All connections successful[/green]")
        sys.exit(0)
    else:
        console.print("[red]✗ Some connections failed[/red]")
        sys.exit(1)


@test.command(name='admin')
@pass_context
def test_admin(ctx: Context):
    """Test Admin API connectivity."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found. Run 'fhenomai config init' first.")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        models = client.list_models()
        console.print(f"[green]✓[/green] Admin API is reachable ({len(models)} models)")
        sys.exit(0)
    except Exception as e:
        console.print(f"[red]✗[/red] Admin API failed: {e}")
        sys.exit(1)


@test.command(name='sftp')
@pass_context
def test_sftp(ctx: Context):
    """Test SFTP connectivity."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found. Run 'fhenomai config init' first.")
        sys.exit(1)
    
    try:
        sftp = SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path,
            auto_connect=True
        )
        sftp.disconnect()
        console.print("[green]✓[/green] SFTP connection successful")
        sys.exit(0)
    except Exception as e:
        console.print(f"[red]✗[/red] SFTP failed: {e}")
        sys.exit(1)


# ============================================================================
# MODEL COMMANDS
# ============================================================================

@cli.group()
def model():
    """Model management commands."""
    pass


@model.command()
@click.option('--online-only', is_flag=True, help='Show only online models')
@click.option('--format', 'output_format', type=click.Choice(['table', 'json', 'yaml']), default='table', help='Output format')
@pass_context
def list(ctx: Context, online_only: bool, output_format: str):
    """List available models."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        if online_only:
            models = client.list_online_models()
        else:
            model_ids = client.list_models()
            # Get online models for status
            online = client.list_online_models()
            online_ids = {m['name'] for m in online}
            
            models = [
                {'id': mid, 'status': 'online' if mid in online_ids else 'offline'}
                for mid in model_ids
            ]
        
        if output_format == 'json':
            print(json.dumps({'models': models}, indent=2))
        elif output_format == 'yaml':
            print(yaml.dump({'models': models}, default_flow_style=False))
        else:
            # Table format
            if not models:
                console.print("[yellow]No models found[/yellow]")
                return
            
            table = Table(title=f"Available Models ({len(models)})")
            table.add_column("Model ID", style="cyan")
            table.add_column("Status", style="green")
            
            for model in models:
                if isinstance(model, dict):
                    status = model.get('status', 'unknown')
                    model_id = model.get('id') or model.get('name')
                else:
                    model_id = model
                    status = 'offline'
                
                status_style = "green" if status == "online" else "dim"
                table.add_row(model_id, f"[{status_style}]{status}[/{status_style}]")
            
            console.print(table)
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command()
@click.argument('model_id')
@pass_context
def info(ctx: Context, model_id: str):
    """Get detailed model information."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        info = client.get_model_info(model_id)
        
        console.print(f"\n[bold]Model:[/bold] {model_id}\n")
        
        table = Table(show_header=False, box=None)
        table.add_column("Key", style="cyan")
        table.add_column("Value")
        
        for key, value in info.items():
            table.add_row(key, str(value))
        
        console.print(table)
        console.print()
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command()
@click.argument('local_path', type=click.Path(exists=True))
@click.argument('model_name')
@click.option('--show-progress/--no-progress', default=True, help='Show upload progress')
@pass_context
def upload(ctx: Context, local_path: str, model_name: str, show_progress: bool):
    """Upload a model to the server."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        remote_path = f"{ctx.config.sftp_models_dir}/{model_name}"
        
        console.print(f"Uploading [cyan]{local_path}[/cyan] as [cyan]{model_name}[/cyan]...")
        
        with SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path
        ) as sftp:
            if Path(local_path).is_file():
                sftp.upload_file(local_path, f"{remote_path}/{Path(local_path).name}")
            else:
                sftp.upload_directory(local_path, remote_path)
        
        console.print(f"[green]✓[/green] Uploaded to {remote_path}")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command()
@click.argument('model_name')
@click.argument('local_path', type=click.Path())
@click.option('--show-progress/--no-progress', default=True, help='Show download progress')
@pass_context
def download(ctx: Context, model_name: str, local_path: str, show_progress: bool):
    """Download a model from the server."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        remote_path = f"{ctx.config.sftp_models_dir}/{model_name}"
        
        console.print(f"Downloading [cyan]{model_name}[/cyan] to [cyan]{local_path}[/cyan]...")
        
        with SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path
        ) as sftp:
            sftp.download_directory(remote_path, local_path)
        
        console.print(f"[green]✓[/green] Downloaded to {local_path}")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command()
@click.argument('model_name_or_path')
@click.argument('out_encrypted_model_path')
@click.option('--wait/--no-wait', default=True, help='Wait for completion')
@click.option('--encryption-impl', default='decoder-only-llm', help='Encryption implementation')
@click.option('--dtype', default='bfloat16', help='Data type')
@click.option('--encrypted-model-id', default=None, help='Custom encrypted model ID/name')
@click.option('--symbolic-name', default=None, help='Symbolic name for the encrypted model')
@click.option('--server-ip', default='fhenom_ai_server', help='FHEnom AI Server hostname/IP')
@click.option('--server-port', type=int, default=9100, help='Server admin port')
@click.option('--preprocessing-impl', default='default', help='Preprocessing strategy')
@click.option('--inference-mode', default='double_tokenizer', help='Inference mode')
@click.option('--driver-mode', default='safetensor', help='Model driver mode')
@click.option('--model-key-password', default=None, help='Password for model encryption keys')
@click.option('--show-progress/--no-progress', default=True, help='Show progress')
@click.option('--timeout', type=int, default=3600, help='Timeout in seconds')
@click.option('--force', is_flag=True, help='Skip duplicate name check')
@pass_context
def encrypt(ctx: Context, model_name_or_path: str, out_encrypted_model_path: str, wait: bool,
            encryption_impl: str, dtype: str, encrypted_model_id: Optional[str], symbolic_name: Optional[str],
            server_ip: str, server_port: int, preprocessing_impl: str, inference_mode: str, driver_mode: str,
            model_key_password: Optional[str], show_progress: bool, timeout: int, force: bool):
    """Encrypt a model."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(config=ctx.config)
        
        # Normalize paths: add upload/ or download/ if not present
        if not model_name_or_path.startswith('upload/') and not model_name_or_path.startswith('/models/upload/'):
            model_name_or_path = f"upload/{model_name_or_path}"
        
        if not out_encrypted_model_path.startswith('download/') and not out_encrypted_model_path.startswith('/models/download/'):
            out_encrypted_model_path = f"download/{out_encrypted_model_path}"
        
        # Extract model name for duplicate check
        output_model_name = out_encrypted_model_path.replace('download/', '').replace('/models/download/', '')
        
        # Check for duplicate names unless --force flag is used
        if not force:
            try:
                model_ids = client.admin.list_models()
                existing_names = []
                
                for model_id in model_ids:
                    try:
                        info = client.admin.get_model_info(model_id)
                        server_path = info.get('encrypted_model_server_path', '')
                        if server_path.startswith('/models/download/'):
                            existing_name = server_path.replace('/models/download/', '', 1)
                            if existing_name == output_model_name:
                                existing_names.append(model_id)
                    except:
                        pass
                
                if existing_names:
                    console.print(f"\n[yellow]⚠ Warning:[/yellow] The name '[cyan]{output_model_name}[/cyan]' is already used by {len(existing_names)} model(s):")
                    for existing_id in existing_names[:3]:  # Show first 3
                        console.print(f"  • {existing_id}")
                    if len(existing_names) > 3:
                        console.print(f"  ... and {len(existing_names) - 3} more")
                    
                    console.print("\n[dim]Note: The new encrypted model will have a unique ID, but using the same name may cause confusion when listing models.[/dim]\n")
                    
                    if not click.confirm("Do you want to proceed with this name?", default=False):
                        new_name = click.prompt("Enter a new output name (without download/ prefix)", type=str)
                        out_encrypted_model_path = f"download/{new_name}"
                        output_model_name = new_name
                        console.print(f"\n[green]✓[/green] Using new name: [cyan]{output_model_name}[/cyan]\n")
            except Exception as e:
                # If check fails, just warn and continue
                console.print(f"[yellow]Warning:[/yellow] Could not check for duplicate names: {e}")
        
        console.print(f"Encrypting [cyan]{model_name_or_path}[/cyan] → [cyan]{out_encrypted_model_path}[/cyan]...")
        
        input_path = f"/{ctx.config.sftp_models_dir}/{model_name_or_path}"
        output_path = f"/{ctx.config.sftp_models_dir}/{out_encrypted_model_path}"
        
        job_id = client.encrypt_model(
            model_name_or_path=input_path,
            out_encrypted_model_path=output_path,
            symbolic_name=symbolic_name,
            server_ip=server_ip,
            server_port=server_port,
            encryption_impl=encryption_impl,
            preprocessing_impl=preprocessing_impl,
            inference_mode=inference_mode,
            driver_mode=driver_mode,
            dtype=dtype,
            model_key_password=model_key_password,
            encrypted_model_id=encrypted_model_id
        )
        
        console.print(f"Job started: [cyan]{job_id}[/cyan]")
        
        if wait:
            if show_progress:
                with Progress(
                    SpinnerColumn(),
                    TextColumn("[progress.description]{task.description}"),
                    console=console
                ) as progress:
                    task = progress.add_task("Encrypting...", total=None)
                    
                    def callback(status):
                        progress_pct = status.get('progress', 0) * 100
                        message = status.get('message', '')
                        progress.update(task, description=f"{message} ({progress_pct:.1f}%)")
                    
                    result = client.wait_for_job(job_id, timeout=timeout, callback=callback)
            else:
                console.print("Waiting for completion...")
                result = client.wait_for_job(job_id, timeout=timeout)
            
            console.print(f"[green]✓[/green] Encryption completed")
            
            # Show encrypted model ID if available
            if result.get('status') == 'done' and 'result' in result:
                encrypted_model_id_result = result['result'].get('encrypted_model_id')
                if encrypted_model_id_result:
                    console.print(f"[cyan]Encrypted Model ID:[/cyan] {encrypted_model_id_result}")
        else:
            console.print("Use 'fhenomai job status' to check progress")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command(name='list')
@click.option('--format', 'output_format', type=click.Choice(['table', 'json']), default='table', help='Output format')
@click.option('--show-status', is_flag=True, help='Show online/offline status (requires additional API call)')
@click.option('--show-details', is_flag=True, help='Show detailed info like encryption impl and dtype (requires API calls per model)')
@pass_context
def list_models_cmd(ctx: Context, output_format: str, show_status: bool, show_details: bool):
    """List all encrypted models on the TEE server."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found. Run 'fhenomai config init' first.")
        sys.exit(1)
    
    try:
        client = FHEnomClient(config=ctx.config)
        model_ids = client.admin.list_models()
        
        # Get online models if status requested
        online_model_ids = set()
        if show_status:
            try:
                online_models = client.admin.list_online_models()
                # Extract model IDs from online models list
                for model in online_models:
                    online_model_ids.add(model.get('name', ''))
            except:
                pass  # If we can't get online status, just continue
        
        # Fetch detailed info for each model if requested
        models = []
        for model_id in model_ids:
            model_data = {
                "encrypted_model_id": model_id,
                "model_name": model_id.split('/')[-1]  # Default fallback
            }
            
            if show_details:
                try:
                    info = client.admin.get_model_info(model_id)
                    # Extract model name from encrypted_model_server_path
                    server_path = info.get('encrypted_model_server_path', '')
                    if server_path.startswith('/models/download/'):
                        model_data["model_name"] = server_path.replace('/models/download/', '', 1)
                    else:
                        model_data["model_name"] = server_path.split('/')[-1] if server_path else model_id.split('/')[-1]
                    
                    model_data["encryption_impl"] = info.get('encryption_impl', 'unknown')
                    model_data["dtype"] = info.get('dtype', 'unknown')
                except:
                    pass  # Use defaults if we can't get info
            
            if show_status:
                model_data["status"] = "online" if model_id in online_model_ids else "offline"
            
            models.append(model_data)
        
        if output_format == 'json':
            import json
            print(json.dumps({"models": models}, indent=2))
        else:
            if not models:
                console.print("[yellow]No encrypted models found[/yellow]")
                return
            
            from rich.table import Table
            table = Table(title="Encrypted Models", show_header=True, header_style="bold magenta")
            table.add_column("Encrypted Model ID", style="cyan")
            
            if show_details:
                table.add_column("Model Name", style="green")
                table.add_column("Encryption", style="yellow")
            
            if show_status:
                table.add_column("Status", style="blue")
            
            for model in models:
                row = [model['encrypted_model_id']]
                
                if show_details:
                    row.append(model['model_name'])
                    row.append(model.get('encryption_impl', 'N/A'))
                
                if show_status:
                    status = model.get('status', 'unknown')
                    if status == 'online':
                        row.append('[green]●[/green] online')
                    else:
                        row.append('[dim]○[/dim] offline')
                
                table.add_row(*row)
            
            console.print(table)
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command(name='encrypt-dataset')
@click.option('--encrypted-model-id', required=True, help='Encrypted model ID to use')
@click.option('--dataset-path', required=True, help='Path to dataset on server (e.g., /models/upload/dataset)')
@click.option('--output-path', required=True, help='Output-path for encrypted dataset (e.g., /models/download/dataset_enc)')
@click.option('--encryption-impl', default='numeric', help='Dataset encryption implementation')
@click.option('--text-fields', multiple=True, help='Text fields to encrypt (can specify multiple times)')
@click.option('--wait/--no-wait', default=True, help='Wait for completion')
@click.option('--show-progress/--no-progress', default=True, help='Show progress')
@click.option('--timeout', type=int, default=3600, help='Timeout in seconds')
@pass_context
def encrypt_dataset(ctx: Context, encrypted_model_id: str, dataset_path: str, output_path: str,
                    encryption_impl: str, text_fields: tuple, wait: bool, show_progress: bool, timeout: int):
    """Encrypt a dataset using an encrypted model."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(config=ctx.config)
        
        # Normalize paths: add upload/ or download/ if not present
        if not dataset_path.startswith('upload/') and not dataset_path.startswith('/models/upload/'):
            dataset_path = f"upload/{dataset_path}"
        
        if not output_path.startswith('download/') and not output_path.startswith('/models/download/'):
            output_path = f"download/{output_path}"
        
        console.print(f"Encrypting dataset [cyan]{dataset_path}[/cyan] → [cyan]{output_path}[/cyan]...")
        console.print(f"Using encrypted model: [cyan]{encrypted_model_id}[/cyan]")
        
        # Convert text_fields tuple to list using list comprehension
        # Note: list(text_fields) causes issues, so we use comprehension instead
        text_fields_list = [x for x in text_fields] if text_fields else ["text"]
        
        job_id = client.admin.encrypt_dataset(
            encrypted_model_id=encrypted_model_id,
            server_ip="fhenom_ai_server",
            server_port=9100,
            dataset_name_or_path=dataset_path,
            out_encrypted_dataset_path=output_path,
            dataset_encryption_impl=encryption_impl,
            text_fields=text_fields_list
        )
        
        console.print(f"Job started: [cyan]{job_id}[/cyan]")
        
        if wait:
            console.print("Waiting for completion...")
            
            with Progress(
                SpinnerColumn(),
                TextColumn("[progress.description]{task.description}"),
                console=console
            ) as progress:
                task = progress.add_task("Encrypting dataset...", total=None)
                
                def callback(status):
                    progress_pct = status.get('progress', 0) * 100
                    message = status.get('message', '')
                    progress.update(task, description=f"{message} ({progress_pct:.1f}%)")
                
                result = client.wait_for_job(job_id, timeout=timeout, callback=callback)
            
            if result.get('status') == 'done':
                console.print(f"[green]✓[/green] Dataset encryption completed")
            else:
                console.print(f"[yellow]⚠[/yellow] Job finished with status: {result.get('status')}")
                if 'error' in result:
                    console.print(f"[red]Error:[/red] {result['error']}")
        else:
            console.print("Use 'fhenomai job status' to check progress")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command()
@click.argument('model_name')
@click.option('--force', is_flag=True, help='Delete without confirmation')
@pass_context
def delete(ctx: Context, model_name: str, force: bool):
    """Delete a model from the server (SFTP-based upload/download directories)."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    if not force:
        if not click.confirm(f"Are you sure you want to delete '{model_name}'?"):
            console.print("[yellow]Cancelled[/yellow]")
            return
    
    try:
        remote_path = f"{ctx.config.sftp_models_dir}/{model_name}"
        
        with SFTPClient(
            host=ctx.config.sftp_host,
            port=ctx.config.sftp_port,
            username=ctx.config.sftp_username,
            password=ctx.config.sftp_password,
            key_path=ctx.config.sftp_key_path
        ) as sftp:
            sftp.delete_directory(remote_path)
        
        console.print(f"[green]✓[/green] Deleted {model_name}")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@model.command(name='delete-encrypted')
@click.argument('model_id')
@click.option('--force', is_flag=True, help='Delete without confirmation')
@pass_context
def delete_encrypted(ctx: Context, model_id: str, force: bool):
    """Delete an encrypted model from TEE storage (local only, does not propagate to peers)."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    if not force:
        console.print(f"\n[yellow]Warning:[/yellow] This will delete the encrypted model: [cyan]{model_id}[/cyan]")
        console.print("[dim]Note: This is a local operation and will not propagate to peer instances.[/dim]\n")
        
        if not click.confirm("Are you sure you want to continue?"):
            console.print("[yellow]Cancelled[/yellow]")
            return
    
    try:
        client = FHEnomClient(ctx.config)
        result = client.admin.delete_encrypted_model(model_id)
        
        console.print(f"[green]✓[/green] Deleted encrypted model: {model_id}")
        
        # Show peer response if available
        if 'embedded_server_response_code' in result:
            code = result['embedded_server_response_code']
            if code == -255:
                console.print("[dim]Note: Embedded server not connected (deleted locally only)[/dim]")
            else:
                console.print(f"[dim]Embedded server response code: {code}[/dim]")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


# ============================================================================
# SERVE COMMANDS  
# ============================================================================

@cli.group()
def serve():
    """Model serving commands."""
    pass


@serve.command()
@click.argument('encrypted_model_id')
@click.option('--server-url', required=True, help='vLLM/TGI server URL')
@click.option('--api-key', help='Optional API key')
@click.option('--display-model-name', help='Display model name for vLLM --served-model-name')
@pass_context
def start(ctx: Context, encrypted_model_id: str, server_url: str,
          api_key: Optional[str], display_model_name: Optional[str]):
    """Start serving an encrypted model."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        console.print(f"Starting serving for [cyan]{encrypted_model_id}[/cyan]...")
        
        response = client.admin.start_serving(
            encrypted_model_id=encrypted_model_id,
            server_url=server_url,
            api_key=api_key,
            display_model_name=display_model_name
        )
        
        console.print(f"[green]✓[/green] {response.get('response', 'Serving started')}")
        console.print(f"\n[dim]Note: Startup takes 1-2 minutes for TEE initialization[/dim]")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@serve.command()
@click.argument('encrypted_model_id')
@pass_context
def stop(ctx: Context, encrypted_model_id: str):
    """Stop serving a model."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        console.print(f"Stopping serving for [cyan]{encrypted_model_id}[/cyan]...")
        
        response = client.admin.stop_serving(encrypted_model_id)
        
        console.print(f"[green]✓[/green] {response.get('response', 'Serving stopped')}")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@serve.command()
@pass_context
def list(ctx: Context):
    """List currently served models."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        models = client.list_online_models()
        
        if not models:
            console.print("[yellow]No models currently served[/yellow]")
            return
        
        table = Table(title=f"Online Models ({len(models)})")
        table.add_column("Model ID", style="cyan")
        table.add_column("Status", style="green")
        
        for model in models:
            table.add_row(model.get('name', 'unknown'), model.get('status', 'online'))
        
        console.print(table)
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


# ============================================================================
# JOB COMMANDS
# ============================================================================

@cli.group()
def job():
    """Job management commands."""
    pass


@job.command()
@click.argument('job_id')
@click.option('--format', 'output_format', type=click.Choice(['table', 'json']), default='table')
@pass_context
def status(ctx: Context, job_id: str, output_format: str):
    """Check job status."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        status = client.get_job_status(job_id)
        
        if output_format == 'json':
            print(json.dumps(status, indent=2))
        else:
            console.print(f"\n[bold]Job:[/bold] {job_id}\n")
            
            table = Table(show_header=False, box=None)
            table.add_column("Key", style="cyan")
            table.add_column("Value")
            
            table.add_row("Status", status.get('status', 'unknown'))
            table.add_row("Progress", f"{status.get('progress', 0) * 100:.1f}%")
            table.add_row("Message", status.get('message', ''))
            
            if status.get('error'):
                table.add_row("Error", f"[red]{status['error']}[/red]")
            
            console.print(table)
            console.print()
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@job.command()
@click.argument('job_id')
@click.option('--timeout', type=int, default=3600, help='Timeout in seconds')
@pass_context
def wait(ctx: Context, job_id: str, timeout: int):
    """Wait for job completion."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        console.print(f"Waiting for job [cyan]{job_id}[/cyan]...")
        
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            console=console
        ) as progress:
            task = progress.add_task("Processing...", total=None)
            
            def callback(status):
                progress_pct = status.get('progress', 0) * 100
                message = status.get('message', '')
                progress.update(task, description=f"{message} ({progress_pct:.1f}%)")
            
            result = client.wait_for_job(job_id, timeout=timeout, callback=callback)
        
        console.print(f"[green]✓[/green] Job completed")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


# ============================================================================
# ADMIN COMMANDS (Advanced Features)
# ============================================================================

@cli.group()
def admin():
    """Advanced administration commands."""
    pass


@admin.group()
def sync():
    """Peer-to-peer synchronization commands."""
    pass


@sync.command()
@click.argument('peer_url')
@click.option('--peer-port', type=int, default=9099, help='Peer admin port (default: 9099)')
@click.option('--format', 'output_format', type=click.Choice(['table', 'json']), default='table', help='Output format')
@pass_context
def start(ctx: Context, peer_url: str, peer_port: int, output_format: str):
    """
    Start peer-to-peer synchronization with another instance.
    
    Initiates synchronization with a peer FHEnom AI instance, performing mutual
    authentication and exchanging encrypted model inventories.
    
    Prerequisites:
    
        - Both instances must have compatible certificates (same root CA and client_id)
        
        - Bidirectional network connectivity on admin port
        
        - Both instances must be properly provisioned
    
    Examples:
    
        # Synchronize with peer at IP address
        
        fhenomai admin sync start http://192.168.1.100
        
        # Synchronize with peer at custom port
        
        fhenomai admin sync start http://peer.example.com --peer-port 9099
        
        # Get JSON output
        
        fhenomai admin sync start http://192.168.1.100 --format json
    """
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        
        console.print(f"Initiating synchronization with [cyan]{peer_url}:{peer_port}[/cyan]...")
        
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            console=console
        ) as progress:
            task = progress.add_task("Synchronizing...", total=None)
            
            result = client.admin.sync.start(
                peer_url=peer_url,
                peer_port=peer_port
            )
        
        if output_format == 'json':
            print(json.dumps(result, indent=2))
        else:
            console.print(f"\n[green]✓[/green] Synchronization completed successfully\n")
            
            table = Table(show_header=False, box=None)
            table.add_column("Key", style="cyan")
            table.add_column("Value")
            
            table.add_row("Job ID", result.get('job_id', 'N/A'))
            table.add_row("Status", result.get('status', 'unknown'))
            table.add_row("Peer Identity", result.get('peer_identity', 'N/A'))
            
            if result.get('models_synced') is not None:
                table.add_row("Models Synced", str(result['models_synced']))
            
            if result.get('message'):
                table.add_row("Message", result['message'])
            
            console.print(table)
            console.print()
            
            console.print("[dim]Note: Peers are now neighbors and will automatically notify each other of new models.[/dim]")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@admin.command()
@click.option('--output', '-o', type=click.Path(), help='Save attestation report to file')
@click.option('--nonce', help='Custom nonce (128 hex characters). Auto-generated if not provided.')
@click.option('--show-nonce', is_flag=True, help='Display the nonce used')
@click.option('--format', '-f', type=click.Choice(['standard', 'detailed']), default='standard',
              help='Output format (standard=parsed fields, detailed=colored hex dump)')
@pass_context
def attestation(ctx: Context, output: Optional[str], nonce: Optional[str], show_nonce: bool, format: str):
    """
    Request TEE attestation report for verification.
    
    This command generates a TEE attestation report that can be verified to confirm
    the service is running in a genuine Trusted Execution Environment (TEE).
    
    The attestation process:
    
        1. Generate or use provided cryptographic nonce (64 bytes)
        
        2. Request attestation report from TEE with the nonce
        
        3. TEE generates signed report including the nonce
        
        4. Report can be verified using TEE verification libraries
    
    Examples:
    
        # Generate attestation with auto-generated nonce
        
        fhenomai admin attestation --output report.bin
        
        # Use custom nonce and display it
        
        fhenomai admin attestation --nonce "a1b2c3..." --show-nonce
        
        # Save report and show nonce for verification
        
        fhenomai admin attestation -o report.bin --show-nonce
    
    Note:
        Requires TEE hardware (AMD SEV, Intel TDX, etc.) to be available.
        Without TEE, this command will fail with a "TEE not available" error.
    """
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        from .utils import generate_nonce, format_nonce_hex
        
        client = FHEnomClient(ctx.config)
        
        # Generate or validate nonce
        if nonce:
            # Validate custom nonce
            if len(nonce) != 128:
                console.print(f"[red]Error:[/red] Nonce must be exactly 128 hex characters (64 bytes), got {len(nonce)}")
                sys.exit(1)
            try:
                bytes.fromhex(nonce)
            except ValueError:
                console.print("[red]Error:[/red] Nonce must be valid hexadecimal")
                sys.exit(1)
            nonce_hex = nonce
        else:
            # Generate random nonce
            nonce_bytes = generate_nonce(64)
            nonce_hex = format_nonce_hex(nonce_bytes)
        
        if show_nonce:
            console.print(f"\n[cyan]Nonce:[/cyan] {nonce_hex}\n")
        
        console.print("Requesting TEE attestation report...")
        
        report_bytes = client.admin.attestation(nonce_hex)
        
        console.print(f"[green]✓[/green] Received attestation report ({len(report_bytes)} bytes)")
        
        # Always save .bin file and nonce if output is specified
        bin_output = None
        if output:
            ext = Path(output).suffix.lower()
            if ext in ['.html', '.pdf', '.txt']:
                # Infer format from extension and save .bin alongside
                bin_output = str(Path(output).with_suffix('.bin'))
            else:
                # Assume it's the bin file
                bin_output = output
            
            with open(bin_output, 'wb') as f:
                f.write(report_bytes)
            
            # Save nonce alongside
            nonce_file = str(Path(bin_output).with_suffix('.nonce'))
            with open(nonce_file, 'w') as f:
                f.write(nonce_hex)
            
            console.print(f"[green]✓[/green] Report saved to: [cyan]{bin_output}[/cyan]")
            console.print(f"[green]✓[/green] Nonce saved to: [cyan]{nonce_file}[/cyan]")
        
        # Format output based on --format flag
        from fhenomai.attestation_formatter import AttestationReportFormatter
        formatter = AttestationReportFormatter()
        
        if format == 'detailed':
            formatted = formatter.format_detailed(report_bytes, bytes.fromhex(nonce_hex))
            # Use print() directly to preserve ANSI color codes
            print(formatted)
        else:
            # Standard format (parsed fields)
            formatted = formatter.format_standard(report_bytes)
            print(formatted)
        
        # If output specified with recognized extension, save formatted version
        if output:
            ext = Path(output).suffix.lower()
            if ext == '.html':
                html = formatter.format_html(report_bytes, bytes.fromhex(nonce_hex))
                Path(output).write_text(html)
                console.print(f"[green]✓[/green] HTML report saved to: [cyan]{output}[/cyan]")
            elif ext == '.pdf':
                try:
                    formatter.format_pdf(report_bytes, bytes.fromhex(nonce_hex), output_path=output)
                    console.print(f"[green]✓[/green] PDF report saved to: [cyan]{output}[/cyan]")
                except ImportError as e:
                    console.print(f"[red]Error:[/red] PDF generation requires reportlab")
                    console.print(f"[dim]Details: {e}[/dim]")
                    console.print("\nInstall PDF dependency:")
                    console.print("  [cyan]pip install reportlab[/cyan]")
                    sys.exit(1)
            elif ext == '.txt':
                # Save formatted text
                if format == 'detailed':
                    formatted_text = formatter.format_detailed(report_bytes, bytes.fromhex(nonce_hex))
                else:
                    formatted_text = formatter.format_standard(report_bytes)
                # Remove ANSI codes for text file
                import re
                clean_text = re.sub(r'\x1b\[[0-9;]*m', '', formatted_text)
                Path(output).write_text(clean_text)
                console.print(f"[green]✓[/green] Text report saved to: [cyan]{output}[/cyan]")
            elif ext not in ['', '.bin']:
                console.print(f"[yellow]Warning:[/yellow] Unsupported format '{ext}'. Supported: .html, .pdf, .txt, .bin")
        
        # If output specified with recognized extension, save formatted version
        if output:
            ext = Path(output).suffix.lower()
            if ext == '.html':
                html = formatter.format_html(report_bytes, bytes.fromhex(nonce_hex))
                Path(output).write_text(html)
                console.print(f"[green]✓[/green] HTML report saved to: [cyan]{output}[/cyan]")
            elif ext == '.pdf':
                formatter.format_pdf(report_bytes, bytes.fromhex(nonce_hex), output_path=output)
                console.print(f"[green]✓[/green] PDF report saved to: [cyan]{output}[/cyan]")
            elif ext == '.txt':
                # Save formatted text
                if format == 'detailed':
                    formatted_text = formatter.format_detailed(report_bytes, bytes.fromhex(nonce_hex))
                else:
                    formatted_text = formatter.format_standard(report_bytes)
                # Remove ANSI codes for text file
                import re
                clean_text = re.sub(r'\x1b\[[0-9;]*m', '', formatted_text)
                Path(output).write_text(clean_text)
                console.print(f"[green]✓[/green] Text report saved to: [cyan]{output}[/cyan]")
            elif ext not in ['', '.bin']:
                console.print(f"[yellow]Warning:[/yellow] Unsupported format '{ext}'. Supported: .html, .pdf, .txt, .bin")
        
        console.print("\n[bold]Next Steps:[/bold]")
        console.print("  1. Verify the report using 'fhenomai admin verify-attestation'")
        console.print("  2. Confirm the nonce matches your request")
        console.print()
        
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)
    except Exception as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)


@admin.command(name='verify-attestation')
@click.option('--report', '-r', type=click.Path(exists=True), required=True, help='Path to attestation report file')
@click.option('--nonce', required=False, help='Expected nonce (128 hex characters). Reads from .nonce file if not provided.')
@click.option('--platform', type=click.Choice(['amd_sev_snp', 'intel_tdx']), default='amd_sev_snp', help='TEE platform type')
@click.option('--json-output', '-j', is_flag=True, help='Output as JSON')
@click.option('--format', '-f', type=click.Choice(['standard', 'detailed']), default='standard',
              help='Output format (standard=parsed fields, detailed=colored hex dump)')
@click.option('--output', '-o', type=click.Path(), help='Save formatted output')
@pass_context
def verify_attestation(ctx: Context, report: str, nonce: Optional[str], platform: str, json_output: bool, format: str, output: Optional[str]):
    """
    Verify a TEE attestation report.
    
    This command verifies the cryptographic authenticity of a TEE attestation report,
    ensuring it was generated by genuine TEE hardware and is bound to the expected nonce.
    
    Verification process:
    
        1. Parse the attestation report structure
        
        2. Verify the report signature using TEE platform certificates
        
        3. Validate the certificate chain (AMD KDS for SEV-SNP)
        
        4. Confirm the nonce is correctly bound to the report
    
    Examples:
    
        # Verify an AMD SEV-SNP attestation report
        
        fhenomai admin verify-attestation --report report.bin --nonce "a1b2c3..."
        
        # Verify with JSON output
        
        fhenomai admin verify-attestation -r report.bin --nonce "a1b2..." -j
        
        # Verify Intel TDX report
        
        fhenomai admin verify-attestation -r report.bin --nonce "a1b2..." --platform intel_tdx
    
    Requirements:
        Attestation support is included with fhenomai installation.
    """
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        # Read the report file
        with open(report, 'rb') as f:
            report_bytes = f.read()
        
        if not report_bytes:
            console.print(f"[red]Error:[/red] Report file is empty: {report}")
            sys.exit(1)
        
        # Try to read nonce from .nonce file if not provided
        if not nonce:
            nonce_file = str(Path(report).with_suffix('.nonce'))
            if Path(nonce_file).exists():
                with open(nonce_file, 'r') as f:
                    nonce = f.read().strip()
                console.print(f"[dim]Loaded nonce from: {nonce_file}[/dim]")
            else:
                console.print(f"[red]Error:[/red] Nonce not provided and {nonce_file} not found")
                sys.exit(1)
        
        # Validate nonce
        if len(nonce) != 128:
            console.print(f"[red]Error:[/red] Nonce must be exactly 128 hex characters (64 bytes), got {len(nonce)}")
            sys.exit(1)
        
        try:
            bytes.fromhex(nonce)
        except ValueError:
            console.print("[red]Error:[/red] Nonce must be valid hexadecimal")
            sys.exit(1)
        
        client = FHEnomClient(ctx.config)
        
        console.print(f"\n[bold]Verifying Attestation Report[/bold]\n")
        console.print(f"Report file: [cyan]{report}[/cyan]")
        console.print(f"Report size: {len(report_bytes)} bytes")
        console.print(f"Platform: [cyan]{platform}[/cyan]")
        console.print(f"Nonce: [cyan]{nonce[:32]}...[/cyan]\n")
        
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            console=console
        ) as progress:
            task = progress.add_task("Verifying...", total=None)
            result = client.admin.verify_attestation(report_bytes, nonce, platform)
        
        if json_output:
            print(json.dumps(result, indent=2))
            sys.exit(0 if result['verified'] else 1)
        
        # Format output
        from fhenomai.attestation_formatter import AttestationReportFormatter
        formatter = AttestationReportFormatter()
        
        if format == 'detailed':
            formatted = formatter.format_detailed(report_bytes, bytes.fromhex(nonce), verification_result=result)
            # Use print() directly to preserve ANSI color codes
            print(formatted)
        else:
            # Standard format (parsed fields)
            formatted = formatter.format_standard(report_bytes, verification_result=result)
            print(formatted)
        
        # If output specified, save formatted version based on extension
        if output:
            ext = Path(output).suffix.lower()
            if ext == '.html':
                html = formatter.format_html(report_bytes, bytes.fromhex(nonce), verification_result=result)
                Path(output).write_text(html)
                console.print(f"[green]✓[/green] HTML verification report saved to: [cyan]{output}[/cyan]")
            elif ext == '.pdf':
                try:
                    formatter.format_pdf(report_bytes, bytes.fromhex(nonce), verification_result=result, output_path=output)
                    console.print(f"[green]✓[/green] PDF verification report saved to: [cyan]{output}[/cyan]")
                except ImportError as e:
                    console.print(f"[red]Error:[/red] PDF generation requires reportlab")
                    console.print(f"[dim]Details: {e}[/dim]")
                    console.print("\nInstall PDF dependency:")
                    console.print("  [cyan]pip install reportlab[/cyan]")
                    sys.exit(1)
            elif ext == '.txt':
                # Save formatted text
                if format == 'detailed':
                    formatted_text = formatter.format_detailed(report_bytes, bytes.fromhex(nonce), verification_result=result)
                else:
                    formatted_text = formatter.format_standard(report_bytes, verification_result=result)
                # Remove ANSI codes for text file
                import re
                clean_text = re.sub(r'\x1b\[[0-9;]*m', '', formatted_text)
                Path(output).write_text(clean_text)
                console.print(f"[green]✓[/green] Text verification report saved to: [cyan]{output}[/cyan]")
            else:
                console.print(f"[yellow]Warning:[/yellow] Unsupported format '{ext}'. Supported: .html, .pdf, .txt")
        
        # If output specified, save formatted version based on extension
        if output:
            ext = Path(output).suffix.lower()
            if ext == '.html':
                html = formatter.format_html(report_bytes, bytes.fromhex(nonce), verification_result=result)
                Path(output).write_text(html)
                console.print(f"[green]✓[/green] HTML verification report saved to: [cyan]{output}[/cyan]")
            elif ext == '.pdf':
                formatter.format_pdf(report_bytes, bytes.fromhex(nonce), verification_result=result, output_path=output)
                console.print(f"[green]✓[/green] PDF verification report saved to: [cyan]{output}[/cyan]")
            elif ext == '.txt':
                # Save formatted text
                if format == 'detailed':
                    formatted_text = formatter.format_detailed(report_bytes, bytes.fromhex(nonce), verification_result=result)
                else:
                    formatted_text = formatter.format_standard(report_bytes, verification_result=result)
                # Remove ANSI codes for text file
                import re
                clean_text = re.sub(r'\x1b\[[0-9;]*m', '', formatted_text)
                Path(output).write_text(clean_text)
                console.print(f"[green]✓[/green] Text verification report saved to: [cyan]{output}[/cyan]")
            else:
                console.print(f"[yellow]Warning:[/yellow] Unsupported format '{ext}'. Supported: .html, .pdf, .txt")
        
        # Exit with appropriate code
        sys.exit(0 if result.get('verified') else 1)
        
    except ImportError as e:
        console.print(f"\n[red]Error:[/red] Attestation library not installed")
        console.print("\nTo use attestation verification, reinstall fhenomai:")
        console.print("  [cyan]pip install --upgrade fhenomai[/cyan]\n")
        console.print("Or install standalone:")
        console.print("  [cyan]pip install dk-tee-attestation[/cyan]\n")
        sys.exit(1)
    except FileNotFoundError:
        console.print(f"[red]Error:[/red] Report file not found: {report}")
        sys.exit(1)
    except Exception as e:
        console.print(f"[red]Error:[/red] {e}")
        if ctx.verbose:
            import traceback
            traceback.print_exc()
        sys.exit(1)


# ============================================================================
# SFTP COMMANDS
# ============================================================================

@cli.group()
def sftp():
    """SFTP file transfer commands."""
    pass


@sftp.command()
@click.argument('local_path')
@click.argument('remote_path')
@click.option('--recursive', '-r', is_flag=True, help='Upload directory recursively')
@click.option('--show-progress/--no-progress', default=True, help='Show upload progress')
@pass_context
def upload(ctx: Context, local_path: str, remote_path: str, recursive: bool, show_progress: bool):
    """Upload a file or directory to the server."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        sftp_manager = client.get_sftp_manager()
        
        # Normalize path: add upload/ prefix if not present
        if not remote_path.startswith('upload/') and not remote_path.startswith('download/') and not remote_path.startswith('/'):
            remote_path = f"upload/{remote_path}"
        
        local = Path(local_path)
        
        if not local.exists():
            console.print(f"[red]Error:[/red] Local path does not exist: {local_path}")
            sys.exit(1)
        
        if local.is_dir():
            if not recursive:
                console.print("[red]Error:[/red] Use --recursive flag to upload directories")
                sys.exit(1)
            
            console.print(f"Uploading directory [cyan]{local_path}[/cyan] to [cyan]{remote_path}[/cyan]...")
            sftp_manager.upload_directory(str(local), remote_path)
            console.print(f"[green]✓[/green] Directory uploaded successfully")
        else:
            console.print(f"Uploading file [cyan]{local_path}[/cyan] to [cyan]{remote_path}[/cyan]...")
            sftp_manager.upload_file(str(local), remote_path)
            console.print(f"[green]✓[/green] File uploaded successfully")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)
    finally:
        try:
            sftp_manager.disconnect()
        except:
            pass


@sftp.command()
@click.argument('remote_path')
@click.argument('local_path')
@click.option('--recursive', '-r', is_flag=True, help='Download directory recursively')
@click.option('--show-progress/--no-progress', default=True, help='Show download progress')
@pass_context
def download(ctx: Context, remote_path: str, local_path: str, recursive: bool, show_progress: bool):
    """Download a file or directory from the server."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        sftp_manager = client.get_sftp_manager()
        
        # Normalize path: add download/ prefix if not present
        if not remote_path.startswith('upload/') and not remote_path.startswith('download/') and not remote_path.startswith('/'):
            remote_path = f"download/{remote_path}"
        
        console.print(f"Downloading [cyan]{remote_path}[/cyan] to [cyan]{local_path}[/cyan]...")
        
        if recursive:
            sftp_manager.download_directory(remote_path, local_path)
            console.print(f"[green]✓[/green] Directory downloaded successfully")
        else:
            sftp_manager.download_file(remote_path, local_path)
            console.print(f"[green]✓[/green] File downloaded successfully")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)
    finally:
        try:
            sftp_manager.disconnect()
        except:
            pass


@sftp.command()
@click.argument('remote_path', required=False, default='.')
@pass_context
def list(ctx: Context, remote_path: str):
    """List files in a remote directory."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        sftp_manager = client.get_sftp_manager()
        
        files = sftp_manager.list_files(remote_path)
        
        if not files:
            console.print(f"No files found in [cyan]{remote_path}[/cyan]")
            return
        
        table = Table(title=f"Files in {remote_path}")
        table.add_column("Name", style="cyan")
        table.add_column("Type")
        table.add_column("Size")
        
        for file_info in files:
            name = file_info.name
            is_dir = file_info.is_dir
            size = file_info.size
            
            file_type = "DIR" if is_dir else "FILE"
            size_str = "-" if is_dir else f"{size:,} bytes"
            
            table.add_row(name, file_type, size_str)
        
        console.print(table)
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)
    finally:
        try:
            sftp_manager.disconnect()
        except:
            pass


@sftp.command()
@click.argument('remote_path')
@click.option('--dry-run', is_flag=True, help='Show what would be deleted without actually deleting')
@click.option('--force', is_flag=True, help='Skip confirmation prompt')
@pass_context
def clear(ctx: Context, remote_path: str, dry_run: bool, force: bool):
    """Clear all contents of a remote directory."""
    if ctx.config is None:
        console.print("[red]Error:[/red] No configuration found")
        sys.exit(1)
    
    try:
        client = FHEnomClient(ctx.config)
        sftp_manager = client.get_sftp_manager()
        
        # First, list what will be deleted
        files = sftp_manager.list_files(remote_path)
        
        if not files:
            console.print(f"[yellow]Directory [cyan]{remote_path}[/cyan] is already empty[/yellow]")
            return
        
        # Show what will be deleted
        console.print(f"\n[yellow]Contents of [cyan]{remote_path}[/cyan]:[/yellow]")
        for file_info in files:
            file_type = "DIR" if file_info.is_dir else "FILE"
            console.print(f"  • {file_info.name} ({file_type})")
        
        # Confirm unless force or dry-run
        if not force and not dry_run:
            if not Confirm.ask(f"\n[red]Delete all contents of {remote_path}?[/red]", default=False):
                console.print("[yellow]Cancelled[/yellow]")
                return
        
        # Clear the directory
        files_deleted, dirs_deleted = sftp_manager.clear_directory(remote_path, dry_run=dry_run)
        
        # Count total items that were listed
        total_files = sum(1 for f in files if not f.is_dir)
        total_dirs = sum(1 for f in files if f.is_dir)
        
        if dry_run:
            console.print(f"\n[cyan]Would delete:[/cyan] {files_deleted} files, {dirs_deleted} directories")
        else:
            console.print(f"\n[green]✓ Deleted:[/green] {files_deleted} files, {dirs_deleted} directories")
            
            # Check if some items couldn't be deleted (permission issues)
            if files_deleted < total_files or dirs_deleted < total_dirs:
                failed_files = total_files - files_deleted
                failed_dirs = total_dirs - dirs_deleted
                if failed_files > 0 or failed_dirs > 0:
                    console.print(f"[yellow]⚠ Could not delete:[/yellow] {failed_files} files, {failed_dirs} directories (permission denied)")
                    console.print("[dim]Note: Encrypted files in download/ may have restricted permissions[/dim]")
    
    except FHEnomError as e:
        console.print(f"[red]Error:[/red] {e}")
        sys.exit(1)
    finally:
        try:
            sftp_manager.disconnect()
        except:
            pass


def main():
    """Entry point for CLI."""
    try:
        cli(obj=Context())
    except KeyboardInterrupt:
        console.print("\n[yellow]Interrupted[/yellow]")
        sys.exit(130)
    except Exception as e:
        console.print(f"\n[red]Unexpected error:[/red] {e}")
        if logging.getLogger().level == logging.DEBUG:
            raise
        sys.exit(1)


if __name__ == '__main__':
    main()
