//! CLI entrypoint for s3bolt.

use std::path::PathBuf;
use std::sync::Arc;

use clap::Parser;

use s3bolt::config::{ConcurrencyConfig, CopyConfig, FilterConfig};
use s3bolt::engine::orchestrator;
use s3bolt::progress::reporter::ProgressState;
use s3bolt::types::S3Uri;

#[derive(Parser, Debug)]
#[command(
    name = "s3bolt",
    version,
    about = "High-performance S3 file copy tool",
    long_about = "Copy S3 objects between buckets and prefixes at maximum throughput.\n\
                   Uses server-side copy, adaptive concurrency, and async I/O."
)]
struct Cli {
    /// Source S3 URI (s3://bucket/key or s3://bucket/prefix/).
    source: String,

    /// Destination S3 URI.
    destination: String,

    /// Recursively copy all objects under prefix.
    #[arg(short, long)]
    recursive: bool,

    /// Only copy new or changed objects (compare ETag + size).
    #[arg(long)]
    sync: bool,

    /// List objects that would be copied without actually copying.
    #[arg(long)]
    dry_run: bool,

    /// Verify ETag after copy.
    #[arg(long)]
    verify: bool,

    /// Include only keys matching glob (repeatable).
    #[arg(long, action = clap::ArgAction::Append)]
    include: Vec<String>,

    /// Exclude keys matching glob (repeatable).
    #[arg(long, action = clap::ArgAction::Append)]
    exclude: Vec<String>,

    /// Include only keys matching regex.
    #[arg(long)]
    key_regex: Option<String>,

    /// Minimum object size (e.g., 1MB, 500KB).
    #[arg(long)]
    min_size: Option<u64>,

    /// Maximum object size.
    #[arg(long)]
    max_size: Option<u64>,

    /// Max concurrent copy operations.
    #[arg(short = 'j', long, default_value = "256")]
    concurrency: u32,

    /// Disable adaptive concurrency.
    #[arg(long)]
    no_adaptive: bool,

    /// Checkpoint file path for resume support.
    #[arg(long)]
    checkpoint: Option<PathBuf>,

    /// Resume from existing checkpoint.
    #[arg(long)]
    resume: bool,

    /// Override destination storage class.
    #[arg(long)]
    storage_class: Option<String>,

    /// AWS profile for source bucket.
    #[arg(long)]
    source_profile: Option<String>,

    /// AWS profile for destination bucket.
    #[arg(long)]
    dest_profile: Option<String>,

    /// Progress output mode.
    #[arg(long, default_value = "human")]
    progress: String,

    /// Enable verbose logging.
    #[arg(short, long)]
    verbose: bool,

    /// Suppress all output except errors.
    #[arg(short, long)]
    quiet: bool,
}

fn main() {
    let cli = Cli::parse();

    // Initialize tracing.
    let filter = if cli.verbose {
        "s3bolt=debug"
    } else if cli.quiet {
        "s3bolt=error"
    } else {
        "s3bolt=info"
    };

    tracing_subscriber::fmt()
        .with_env_filter(filter)
        .with_target(false)
        .init();

    // Parse URIs.
    let source = match S3Uri::parse(&cli.source) {
        Ok(uri) => uri,
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    };
    let destination = match S3Uri::parse(&cli.destination) {
        Ok(uri) => uri,
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    };

    let config = CopyConfig {
        source,
        destination,
        recursive: cli.recursive,
        sync_mode: cli.sync,
        dry_run: cli.dry_run,
        verify: cli.verify,
        filters: FilterConfig {
            include_globs: cli.include,
            exclude_globs: cli.exclude,
            key_regex: cli.key_regex,
            min_size: cli.min_size,
            max_size: cli.max_size,
            newer_than: None,
            older_than: None,
        },
        concurrency: ConcurrencyConfig {
            max_concurrent: cli.concurrency,
            adaptive: !cli.no_adaptive,
            ..Default::default()
        },
        checkpoint_path: cli.checkpoint,
        resume: cli.resume,
        storage_class: cli.storage_class,
        sse: None,
        preserve_metadata: false,
        source_profile: cli.source_profile,
        dest_profile: cli.dest_profile,
    };

    let progress = Arc::new(ProgressState::default());

    // Build a multi-threaded Tokio runtime using all available cores.
    let runtime = tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .thread_name("s3bolt-worker")
        .build()
        .unwrap();
    let result = runtime.block_on(orchestrator::run(config, progress));

    match result {
        Ok(manifest) => {
            if !cli.quiet {
                let bytes_str = humansize::format_size(manifest.copied_bytes, humansize::BINARY);
                println!(
                    "\nCopied {} objects ({}) | Skipped {} | Failed {} | {:.1}s",
                    manifest.copied_objects,
                    bytes_str,
                    manifest.skipped_objects,
                    manifest.failed_objects,
                    manifest.duration_secs,
                );
            }
            if manifest.failed_objects > 0 {
                std::process::exit(1);
            }
        }
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    }
}
