"""
CHRONOS Quantum Vault CLI Commands
===================================

Command-line interface for quantum-secure data vault operations.
"""

import json
from pathlib import Path
from datetime import timedelta
from typing import Optional

import typer
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.progress import Progress
from rich.json import JSON

from chronos.core.defend.quantum_vault import (
    QuantumVault,
    VaultAlgorithm,
    CloudProvider,
    VaultOperationType,
    VaultStatus,
    IntegrityStatus,
    create_vault,
    analyze_vault_security,
)

app = typer.Typer(help="Quantum-secure data vault operations")
console = Console()


@app.command()
def create(
    vault_id: Optional[str] = typer.Option(None, "--vault-id", help="Vault identifier"),
    password: Optional[str] = typer.Option(None, "--password", help="Master password"),
    output: Optional[str] = typer.Option(None, "--output", help="Output file for vault config"),
):
    """Create a new quantum vault."""
    console.print(f"\n[cyan]Creating quantum vault...[/cyan]\n")
    
    vault = create_vault(vault_id, password or "")
    
    console.print(f"[green]✓ Vault created[/green]")
    console.print(f"  ID: [cyan]{vault.vault_id}[/cyan]")
    console.print(f"  Status: [yellow]{vault.status.value}[/yellow]")
    console.print(f"  Algorithm: [cyan]{vault.algorithm_agility.current_algorithm.value}[/cyan]")
    console.print(f"  Time: [dim]{vault.created_at.isoformat()}[/dim]")
    
    if output:
        config = {
            'vault_id': vault.vault_id,
            'status': vault.status.value,
            'algorithm': vault.algorithm_agility.current_algorithm.value,
        }
        with open(output, 'w') as f:
            json.dump(config, f, indent=2)
        console.print(f"\n[green]✓ Configuration saved to {output}[/green]")


@app.command()
def seal(
    vault_id: str = typer.Argument(help="Vault ID to seal"),
):
    """Seal a vault."""
    console.print(f"\n[yellow]Sealing vault: {vault_id}[/yellow]\n")
    
    # In production: load vault from storage
    vault = QuantumVault(vault_id)
    vault.unseal_vault()  # Unseal first if needed
    
    if vault.seal_vault():
        console.print(f"[green]✓ Vault sealed successfully[/green]")
        console.print(f"  Status: [yellow]{vault.status.value}[/yellow]")
    else:
        console.print(f"[red]✗ Failed to seal vault[/red]")


@app.command()
def unseal(
    vault_id: str = typer.Argument(help="Vault ID to unseal"),
    password: Optional[str] = typer.Option(None, "--password", help="Master password"),
):
    """Unseal a vault."""
    console.print(f"\n[cyan]Unsealing vault: {vault_id}[/cyan]\n")
    
    vault = QuantumVault(vault_id, password or "")
    
    if vault.unseal_vault(password or ""):
        console.print(f"[green]✓ Vault unsealed successfully[/green]")
        console.print(f"  Status: [cyan]{vault.status.value}[/cyan]")
    else:
        console.print(f"[red]✗ Failed to unseal vault[/red]")


@app.command()
def store(
    vault_id: str = typer.Argument(help="Vault ID"),
    data_file: str = typer.Option(..., "--file", help="File containing data to store"),
    metadata: Optional[str] = typer.Option(None, "--metadata", help="JSON metadata"),
    time_lock: int = typer.Option(0, "--time-lock", help="Time-lock duration in seconds"),
):
    """Store data in vault."""
    console.print(f"\n[cyan]Storing data in vault: {vault_id}[/cyan]\n")
    
    try:
        # Read data
        with open(data_file, 'rb') as f:
            data = f.read()
        
        # Create vault
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        # Parse metadata
        meta_dict = {}
        if metadata:
            meta_dict = json.loads(metadata)
        
        with Progress() as progress:
            task = progress.add_task("Encrypting and storing...", total=3)
            
            # Store secret
            data_id = vault.store_secret(data, metadata=meta_dict, time_lock_seconds=time_lock)
            progress.update(task, advance=1)
            
            # Log
            progress.update(task, advance=1)
            
            # Finalize
            progress.update(task, advance=1)
        
        console.print(f"\n[green]✓ Data stored successfully[/green]")
        console.print(f"  Data ID: [cyan]{data_id}[/cyan]")
        console.print(f"  Size: [yellow]{len(data)} bytes[/yellow]")
        if time_lock > 0:
            console.print(f"  Time-lock: [red]{time_lock}s[/red]")
        
    except Exception as e:
        console.print(f"[red]✗ Error storing data: {str(e)}[/red]")


@app.command()
def retrieve(
    vault_id: str = typer.Argument(help="Vault ID"),
    data_id: str = typer.Argument(help="Data ID to retrieve"),
    output: Optional[str] = typer.Option(None, "--output", help="Output file"),
):
    """Retrieve data from vault."""
    console.print(f"\n[cyan]Retrieving data from vault...[/cyan]\n")
    
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        with Progress() as progress:
            task = progress.add_task("Decrypting...", total=2)
            
            data = vault.retrieve_secret(data_id)
            progress.update(task, advance=1)
            
            progress.update(task, advance=1)
        
        if data:
            console.print(f"[green]✓ Data retrieved successfully[/green]")
            console.print(f"  Size: [yellow]{len(data)} bytes[/yellow]")
            
            if output:
                with open(output, 'wb') as f:
                    f.write(data)
                console.print(f"[green]✓ Data saved to {output}[/green]")
        else:
            console.print(f"[red]✗ Failed to retrieve data[/red]")
            
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def shard(
    vault_id: str = typer.Argument(help="Vault ID"),
    data: str = typer.Option(..., "--data", help="Data to shard (base64)"),
    total: int = typer.Option(5, "--total", help="Total number of shards"),
    threshold: int = typer.Option(3, "--threshold", help="Shards needed to reconstruct"),
):
    """Create Shamir's secret shards."""
    console.print(f"\n[cyan]Creating Shamir shards...[/cyan]\n")
    
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        import base64
        secret = base64.b64decode(data)
        
        with Progress() as progress:
            task = progress.add_task("Creating shards...", total=total)
            
            shards = vault.create_shard_set(secret, total, threshold)
            progress.update(task, advance=total)
        
        console.print(f"\n[green]✓ Shards created[/green]")
        console.print(f"  Total shards: [cyan]{total}[/cyan]")
        console.print(f"  Threshold: [yellow]{threshold}[/yellow]")
        console.print(f"  Secret ID: [magenta]{shards[0].secret_id}[/magenta]\n")
        
        # Display shard table
        table = Table(show_header=True, header_style="bold magenta")
        table.add_column("Index", style="cyan")
        table.add_column("Shard ID", style="green")
        table.add_column("Checksum", style="dim")
        
        for shard in shards[:5]:
            table.add_row(
                str(shard.shard_index),
                shard.shard_id[:16] + "...",
                shard.checksum[:16] + "...",
            )
        
        console.print(table)
        
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def distribute(
    vault_id: str = typer.Argument(help="Vault ID"),
    secret_id: str = typer.Argument(help="Secret ID"),
    providers: str = typer.Option("aws,azure,gcp", "--providers", help="Cloud providers"),
):
    """Distribute shards to cloud providers."""
    console.print(f"\n[cyan]Distributing shards to cloud providers...[/cyan]\n")
    
    try:
        # Parse providers
        provider_list = []
        for p in providers.split(","):
            p = p.strip().lower()
            if p == "aws":
                provider_list.append(CloudProvider.AWS_S3)
            elif p == "azure":
                provider_list.append(CloudProvider.AZURE_BLOB)
            elif p == "gcp":
                provider_list.append(CloudProvider.GCP_CLOUD_STORAGE)
        
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        # Get shards for secret (would load from storage in production)
        if secret_id in vault.shards_map:
            shards = vault.shards_map[secret_id]
            
            with Progress() as progress:
                task = progress.add_task("Distributing...", total=len(shards))
                
                distribution = vault.distribute_shards(shards, provider_list * (len(shards) // len(provider_list) + 1))
                progress.update(task, advance=len(shards))
            
            console.print(f"\n[green]✓ Shards distributed[/green]")
            console.print(f"  Providers: [cyan]{', '.join([p.value for p in provider_list])}[/cyan]")
            console.print(f"  Shards: [yellow]{len(shards)}[/yellow]")
        
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def algorithm(
    vault_id: str = typer.Argument(help="Vault ID"),
    new_algo: str = typer.Option(..., "--switch", help="New algorithm"),
    reason: Optional[str] = typer.Option(None, "--reason", help="Reason for switch"),
):
    """Switch vault encryption algorithm."""
    console.print(f"\n[cyan]Switching encryption algorithm...[/cyan]\n")
    
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        # Parse algorithm
        algo_map = {
            'kyber512': VaultAlgorithm.KYBER_512,
            'kyber768': VaultAlgorithm.KYBER_768,
            'kyber1024': VaultAlgorithm.KYBER_1024,
            'dilithium2': VaultAlgorithm.DILITHIUM_2,
            'dilithium3': VaultAlgorithm.DILITHIUM_3,
            'dilithium5': VaultAlgorithm.DILITHIUM_5,
            'hybrid': VaultAlgorithm.HYBRID_AES_KYBER,
        }
        
        new_algorithm = algo_map.get(new_algo.lower())
        if not new_algorithm:
            console.print(f"[red]✗ Unknown algorithm: {new_algo}[/red]")
            return
        
        if vault.switch_algorithm(new_algorithm, reason or ""):
            console.print(f"[green]✓ Algorithm switched[/green]")
            console.print(f"  From: [yellow]{VaultAlgorithm.HYBRID_AES_KYBER.value}[/yellow]")
            console.print(f"  To: [cyan]{new_algorithm.value}[/cyan]")
            if reason:
                console.print(f"  Reason: [dim]{reason}[/dim]")
        
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def verify(
    vault_id: str = typer.Argument(help="Vault ID"),
    data_id: str = typer.Argument(help="Data ID to verify"),
):
    """Verify data integrity."""
    console.print(f"\n[cyan]Verifying data integrity...[/cyan]\n")
    
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        integrity = vault.verify_data_integrity(data_id)
        
        status_color = {
            IntegrityStatus.VALID: "green",
            IntegrityStatus.INVALID: "red",
            IntegrityStatus.TAMPERED: "red",
            IntegrityStatus.CORRUPTED: "yellow",
        }.get(integrity, "dim")
        
        console.print(f"[{status_color}]✓ Integrity: {integrity.value}[/{status_color}]")
        
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def status(
    vault_id: str = typer.Argument(help="Vault ID"),
    format: str = typer.Option("console", "--format", help="Output format: console, json"),
):
    """Get vault status."""
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        status_info = vault.get_vault_status()
        
        if format == "json":
            console.print_json(data=status_info)
        else:
            console.print(f"\n[bold cyan]Vault Status[/bold cyan]\n")
            
            table = Table(show_header=False)
            table.add_row("ID:", f"[cyan]{status_info['vault_id']}[/cyan]")
            table.add_row("Status:", f"[yellow]{status_info['status']}[/yellow]")
            table.add_row("Algorithm:", f"[cyan]{status_info['current_algorithm']}[/cyan]")
            table.add_row("Encrypted Data:", f"[green]{status_info['total_encrypted_data']}[/green]")
            table.add_row("Shard Sets:", f"[green]{status_info['total_shard_sets']}[/green]")
            table.add_row("Time Locks:", f"[yellow]{status_info['total_time_locks']}[/yellow]")
            table.add_row("Audit Logs:", f"[green]{status_info['audit_log_count']}[/green]")
            table.add_row("Audit Valid:", f"[green]✓[/green]" if status_info['audit_log_integrity_valid'] else f"[red]✗[/red]")
            
            console.print(table)
            
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def metrics(
    vault_id: str = typer.Argument(help="Vault ID"),
):
    """Display vault metrics."""
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        m = vault.get_metrics()
        
        console.print(f"\n[bold cyan]Vault Metrics[/bold cyan]\n")
        
        table = Table(show_header=False)
        table.add_row("Total Operations:", f"[cyan]{m.total_operations}[/cyan]")
        table.add_row("Data Sealed:", f"[green]{m.total_data_sealed} bytes[/green]")
        table.add_row("Data Unsealed:", f"[green]{m.total_data_unsealed} bytes[/green]")
        table.add_row("Shards Created:", f"[cyan]{m.total_shards_created}[/cyan]")
        table.add_row("Shards Distributed:", f"[cyan]{m.total_shards_distributed}[/cyan]")
        table.add_row("Algorithm Changes:", f"[yellow]{m.algorithm_changes}[/yellow]")
        table.add_row("Key Rotations:", f"[yellow]{m.key_rotations}[/yellow]")
        table.add_row("Integrity Checks:", f"[green]{m.integrity_checks}[/green]")
        table.add_row("Integrity Failures:", f"[red]{m.integrity_failures}[/red]" if m.integrity_failures > 0 else f"[green]{m.integrity_failures}[/green]")
        table.add_row("Failed Operations:", f"[red]{m.failed_operations}[/red]" if m.failed_operations > 0 else f"[green]{m.failed_operations}[/green]")
        
        console.print(table)
        
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def audit_log(
    vault_id: str = typer.Argument(help="Vault ID"),
    limit: int = typer.Option(20, "--limit", help="Number of entries to display"),
    format: str = typer.Option("console", "--format", help="Output format: console, json"),
):
    """Display audit log."""
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        logs = vault.get_audit_log(limit)
        
        if format == "json":
            console.print_json(data=logs)
        else:
            console.print(f"\n[bold cyan]Audit Log (Last {limit} entries)[/bold cyan]\n")
            
            table = Table(show_header=True, header_style="bold magenta")
            table.add_column("Time", style="dim", width=20)
            table.add_column("Operation", style="cyan")
            table.add_column("Operator", style="green")
            table.add_column("Status", width=8)
            table.add_column("Details", style="dim")
            
            for log in logs[-limit:]:
                status_color = "green" if log['status'] == 'success' else "red"
                table.add_row(
                    log['timestamp'][-8:],
                    log['operation_type'],
                    log['operator'],
                    f"[{status_color}]{log['status']}[/{status_color}]",
                    str(log.get('details', {}))[:30],
                )
            
            console.print(table)
        
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


@app.command()
def analyze(
    vault_id: str = typer.Argument(help="Vault ID"),
):
    """Analyze vault security."""
    console.print(f"\n[cyan]Analyzing vault security...[/cyan]\n")
    
    try:
        vault = QuantumVault(vault_id)
        vault.unseal_vault()
        
        analysis = analyze_vault_security(vault)
        
        console.print("[bold cyan]Security Analysis[/bold cyan]\n")
        
        console.print(f"[green]✓ Encryption:[/green]")
        console.print(f"  {analysis['encryption_strength']}")
        
        console.print(f"\n[green]✓ Key Sharding:[/green]")
        console.print(f"  {analysis['sharding_scheme']}")
        
        console.print(f"\n[green]✓ Features:[/green]")
        console.print(f"  Time-lock: {'Enabled' if analysis['time_lock_enabled'] else 'Disabled'}")
        console.print(f"  Geographic distribution: {'Enabled' if analysis['geographic_distribution'] else 'Disabled'}")
        console.print(f"  Algorithm agility: {'Supported' if analysis['algorithm_agility'] else 'Not supported'}")
        console.print(f"  Audit integrity: {'Valid' if analysis['audit_integrity'] else 'Invalid'}")
        
    except Exception as e:
        console.print(f"[red]✗ Error: {str(e)}[/red]")


if __name__ == "__main__":
    app()
