"""Configuration upload/download CLI commands.

Provides commands for:
- config download: Download configs from S3 to local directory
- config upload: Upload configs from local directory to S3
- config list: List available configs in S3
"""

from typing import Optional

import typer
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich import box

from src.services.environment_service import EnvironmentService
from src.services.s3_data_service import S3DataService
from src.cz_billing_generator.services.config import (
    ConfigPathResolver,
    ConfigFileHandler,
    ConfigS3Operations,
    ConfigOrchestrator,
)

console = Console()
app = typer.Typer(
    name="config",
    help="Configuration upload/download commands",
    no_args_is_help=True
)


def format_bytes(bytes_count: int) -> str:
    """Format bytes as human-readable string (KB, MB, GB)."""
    if bytes_count == 0:
        return "0 bytes"
    elif bytes_count < 1024:
        return f"{bytes_count} bytes"
    elif bytes_count < 1024 * 1024:
        return f"{bytes_count / 1024:.1f} KB"
    elif bytes_count < 1024 * 1024 * 1024:
        return f"{bytes_count / (1024 * 1024):.1f} MB"
    else:
        return f"{bytes_count / (1024 * 1024 * 1024):.1f} GB"


@app.command("download")
def download_configs(
    prefix: str = typer.Option(
        "czbillgen/configs/",
        "--prefix",
        "-p",
        help="S3 prefix to download from"
    )
):
    """Download configs from S3 to ./czbg-configs/

    Downloads all configuration files (.yaml, .yml, .md) from S3 to your local
    ./czbg-configs/ directory in the current working directory.

    Example:
        czbg config download
        czbg config download --prefix czbillgen/configs/generate/
    """
    try:
        # FAIL FAST: Validate AWS credentials
        env_service = EnvironmentService()
        env_service.validate_aws_credentials_and_access()

        # Initialize services
        s3_service = S3DataService()
        path_resolver = ConfigPathResolver()
        file_handler = ConfigFileHandler()
        s3_operations = ConfigS3Operations(s3_service)
        orchestrator = ConfigOrchestrator(file_handler, path_resolver, s3_operations)

        # Download configs
        console.print(f"📥 [bold blue]Downloading configs from S3...[/bold blue]")
        console.print(f"   Prefix: [cyan]{prefix}[/cyan]")
        console.print(f"   Target: [cyan]./czbg-configs/[/cyan]")

        stats = orchestrator.download(prefix)

        # Show result message
        console.print()
        if stats['files_downloaded'] == 0:
            console.print(Panel.fit(
                f"⚠️  [bold yellow]No config files found[/bold yellow]\n\n"
                f"No configuration files (.yaml, .yml, .md) were found at:\n"
                f"[cyan]s3://{s3_service.bucket}/{prefix}[/cyan]\n\n"
                f"💡 Tip: Check if configs have been uploaded to S3 first.",
                border_style="yellow",
                box=box.ROUNDED
            ))
        else:
            console.print(Panel.fit(
                f"✅ [bold green]Download complete![/bold green]\n\n"
                f"Files downloaded: [cyan]{stats['files_downloaded']}[/cyan]\n"
                f"Total size: [cyan]{format_bytes(stats['bytes_downloaded'])}[/cyan]\n"
                f"Location: [cyan]./czbg-configs/[/cyan]",
                border_style="green",
                box=box.ROUNDED
            ))

    except Exception as e:
        console.print(f"[bold red]Error downloading configs:[/bold red] {str(e)}")
        raise typer.Exit(code=1)


@app.command("upload")
def upload_configs(
    local_path: str = typer.Argument(
        ...,
        help="Local directory to upload from"
    ),
    no_sync: bool = typer.Option(
        False,
        "--no-sync",
        help="Add/update files only (don't delete S3 files not in local)"
    )
):
    """Upload configs from local directory to S3.

    By default, uses SYNC mode (clean slate):
    - Deletes all files from S3 first
    - Then uploads local files
    - Prevents stale/renamed files from accumulating

    Use --no-sync to only add/update files without deleting.

    Example:
        czbg config upload ./czbg-configs/              # Sync mode (clean slate)
        czbg config upload ./czbg-configs/ --no-sync    # Add/update only
    """
    try:
        # FAIL FAST: Validate AWS credentials
        env_service = EnvironmentService()
        env_service.validate_aws_credentials_and_access()

        # Initialize services
        s3_service = S3DataService()
        path_resolver = ConfigPathResolver()
        file_handler = ConfigFileHandler()
        s3_operations = ConfigS3Operations(s3_service)
        orchestrator = ConfigOrchestrator(file_handler, path_resolver, s3_operations)

        # Upload configs
        sync_mode = not no_sync
        if sync_mode:
            console.print(f"📤 [bold blue]Uploading configs to S3 (SYNC mode - clean slate)...[/bold blue]")
        else:
            console.print(f"📤 [bold blue]Uploading configs to S3 (add/update only)...[/bold blue]")
        console.print(f"   Source: [cyan]{local_path}[/cyan]")

        stats = orchestrator.upload(local_path, sync=sync_mode)

        # Show result message
        console.print()
        if stats['files_uploaded'] == 0:
            console.print(Panel.fit(
                f"⚠️  [bold yellow]No config files found[/bold yellow]\n\n"
                f"No configuration files (.yaml, .yml, .md) were found in:\n"
                f"[cyan]{local_path}[/cyan]\n\n"
                f"💡 Tip: Check the directory path and file extensions.",
                border_style="yellow",
                box=box.ROUNDED
            ))
        else:
            # Build result message
            result_lines = [
                f"✅ [bold green]Upload complete![/bold green]\n",
            ]

            if sync_mode and stats['files_deleted'] > 0:
                result_lines.append(f"Files deleted: [cyan]{stats['files_deleted']}[/cyan]")

            result_lines.extend([
                f"Files uploaded: [cyan]{stats['files_uploaded']}[/cyan]",
                f"Total size: [cyan]{format_bytes(stats['bytes_uploaded'])}[/cyan]",
                f"Destination: [cyan]s3://{s3_service.bucket}/czbillgen/configs/[/cyan]"
            ])

            console.print(Panel.fit(
                "\n".join(result_lines),
                border_style="green",
                box=box.ROUNDED
            ))

    except FileNotFoundError as e:
        console.print(f"[bold red]Error:[/bold red] {str(e)}")
        raise typer.Exit(code=1)
    except Exception as e:
        console.print(f"[bold red]Error uploading configs:[/bold red] {str(e)}")
        raise typer.Exit(code=1)


@app.command("list")
def list_configs(
    prefix: str = typer.Option(
        "czbillgen/configs/",
        "--prefix",
        "-p",
        help="S3 prefix to list"
    )
):
    """List available configs in S3.

    Shows all configuration files available in S3 under the specified prefix.

    Example:
        czbg config list
        czbg config list --prefix czbillgen/configs/generate/
    """
    try:
        # FAIL FAST: Validate AWS credentials
        env_service = EnvironmentService()
        env_service.validate_aws_credentials_and_access()

        # Initialize services
        s3_service = S3DataService()
        path_resolver = ConfigPathResolver()
        file_handler = ConfigFileHandler()
        s3_operations = ConfigS3Operations(s3_service)
        orchestrator = ConfigOrchestrator(file_handler, path_resolver, s3_operations)

        # List configs
        console.print(f"📋 [bold blue]Listing configs from S3...[/bold blue]")
        console.print(f"   Prefix: [cyan]{prefix}[/cyan]")

        files = orchestrator.list_configs(prefix)

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

        # Create table
        table = Table(
            title=f"📁 Config Files ({len(files)} found)",
            box=box.ROUNDED,
            show_header=True,
            header_style="bold blue"
        )

        table.add_column("Path", style="cyan", min_width=40)
        table.add_column("Size", style="green", justify="right")
        table.add_column("Last Modified", style="yellow")

        for file_info in files:
            # Extract relative path (remove prefix)
            key = file_info['key']
            relative_path = key.replace(prefix, "", 1).lstrip("/")

            # Format size
            size_str = format_bytes(file_info['size'])

            # Format date
            modified = file_info['last_modified']
            modified_str = modified.strftime("%Y-%m-%d %H:%M")

            table.add_row(relative_path, size_str, modified_str)

        console.print(table)

    except Exception as e:
        console.print(f"[bold red]Error listing configs:[/bold red] {str(e)}")
        raise typer.Exit(code=1)
