use std::ffi::OsString;

use clap::{Subcommand, ValueEnum};
use clap_complete::engine::ArgValueCompleter;

/// Game save management commands
#[derive(Subcommand, Debug, Clone)]
pub enum GameCommands {
    /// Initialize restic repository for game saves
    Init {
        /// Restic repository path to use (non-interactive)
        #[arg(long)]
        repo: Option<String>,
        /// Restic repository password (defaults to built-in password)
        #[arg(long)]
        password: Option<String>,
    },
    /// Add a new game to track
    Add {
        /// Game name (non-interactive)
        #[arg(long)]
        name: Option<String>,
        /// Optional description
        #[arg(long)]
        description: Option<String>,
        /// Optional launch command
        #[arg(long)]
        launch_command: Option<String>,
        /// Save path for the game (non-interactive)
        #[arg(long)]
        save_path: Option<String>,
        /// Create save path automatically when using --save-path
        #[arg(long)]
        create_save_path: bool,
        /// Disable the discovered-games cache for this run
        ///
        /// Cache file: `$XDG_CACHE_HOME/instant/game-discovery-cache.json`
        /// (usually `~/.cache/instant/game-discovery-cache.json`)
        #[arg(long)]
        no_cache: bool,
    },
    /// Discover games available for `ins game add`
    Discover {
        /// Restrict discovery to a specific Wine prefix path or path inside one
        path: Option<String>,
        /// Limit discovery to specific platforms, e.g. `--source ps2 --source epic`
        #[arg(long = "source", value_enum, value_delimiter = ',')]
        sources: Vec<GameDiscoverySourceArg>,
        /// Internal: output streaming menu rows for the add flow
        #[arg(long, hide = true)]
        menu: bool,
        /// Disable the discovered-games cache for this run
        ///
        /// Cache file: `$XDG_CACHE_HOME/instant/game-discovery-cache.json`
        /// (usually `~/.cache/instant/game-discovery-cache.json`)
        #[arg(long)]
        no_cache: bool,
    },
    /// Sync game saves with restic repository
    Sync {
        /// Game name to sync (optional, syncs all if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Force sync even if checkpoint matches
        #[arg(long)]
        force: bool,
    },
    /// Launch a game with automatic save sync
    Launch {
        /// Game name to launch (optional, will prompt if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
    },
    /// Execute a command with pre/post syncs (for Steam game prefixes)
    Exec {
        /// Command to execute (use with Steam %command% placeholder)
        #[arg(required = true, trailing_var_arg = true)]
        command: Vec<OsString>,
    },
    /// List all configured games
    List,
    /// Show detailed information about a game
    Info {
        /// Game name to show (optional, will prompt if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
    },
    /// Interactive game menu (launch or edit games)
    Menu {
        /// Game name (optional, will prompt if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Open the menu in a GUI terminal window
        #[arg(long = "gui")]
        gui: bool,
    },
    /// Remove a game from tracking
    Remove {
        /// Game name to remove (optional, will prompt if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Remove game without interactive confirmation
        #[arg(long)]
        force: bool,
    },
    /// Create a restic backup of game saves
    Backup {
        /// Game name to backup (optional, will prompt if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
    },
    /// Prune game snapshots using a retention policy
    Prune {
        /// Game name to prune (optional, prunes all if not specified)
        #[arg(long, add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Use legacy zero-change pruning behavior
        #[arg(long = "zero-changes")]
        zero_changes: bool,
    },
    /// Run restic commands with instant games repository configuration
    Restic {
        /// Restic command and arguments to execute
        args: Vec<String>,
    },
    /// Restore game saves from a backup snapshot
    Restore {
        /// Game name to restore (optional, will prompt if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Snapshot ID to restore from (optional, will prompt if not specified)
        snapshot_id: Option<String>,
        /// Force restore even if checkpoint matches
        #[arg(long)]
        force: bool,
    },
    /// Set up games that have been added but are not configured on this device
    Setup,
    /// Relocate a game's save path (updates config, does not move files)
    #[command(alias = "move")]
    Relocate {
        /// The new path for the game saves
        path: Option<String>,
        /// Game name (optional, will prompt if not specified)
        #[arg(long, short)]
        game: Option<String>,
    },
    /// Scan a Wine prefix for Ludusavi-compatible save games
    ScanWinePrefix {
        /// Wine prefix path (optional, prompts if omitted)
        prefix: Option<String>,
        /// Print results as a list instead of interactive menu
        #[arg(long)]
        list: bool,
    },
    /// Manage game dependencies
    Deps {
        /// Dependency subcommands
        #[command(subcommand)]
        command: DependencyCommands,
    },
    /// Debug command: Show snapshot tag information (for developers)
    #[cfg(debug_assertions)]
    Debug {
        /// Debug subcommands
        #[command(subcommand)]
        debug_command: DebugCommands,
    },
}

#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum GameDiscoverySourceArg {
    #[value(name = "switch", alias = "eden")]
    Switch,
    #[value(name = "ps2", alias = "pcsx2")]
    Ps2,
    #[value(name = "ps1", alias = "duckstation")]
    Ps1,
    #[value(name = "3ds", alias = "azahar")]
    ThreeDs,
    #[value(name = "epic")]
    Epic,
    #[value(name = "steam")]
    Steam,
    #[value(name = "faugus")]
    Faugus,
    #[value(name = "wine")]
    Wine,
}

/// Dependency management commands
#[derive(Subcommand, Debug, Clone)]
pub enum DependencyCommands {
    /// Add a dependency to a game and snapshot it into restic
    Add {
        /// Game name (optional, prompts if omitted)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Dependency identifier (optional, prompts if omitted)
        dependency_id: Option<String>,
        /// Path to dependency source file or directory (optional, prompts if omitted)
        path: Option<String>,
    },
    /// Install a dependency onto this device
    Install {
        /// Game name (optional, prompts if omitted)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Dependency identifier (optional, prompts if omitted)
        dependency_id: Option<String>,
        /// Destination path (optional, prompts if omitted)
        path: Option<String>,
    },
    /// Remove dependency installation record from this device
    Uninstall {
        /// Game name (optional, prompts if omitted)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
        /// Dependency identifier (optional, prompts if omitted)
        dependency_id: Option<String>,
    },
    /// List dependencies for a game
    List {
        /// Game name (optional, prompts if omitted)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
    },
}

/// Debug commands for developers
#[cfg(debug_assertions)]
#[derive(Subcommand, Debug, Clone)]
pub enum DebugCommands {
    /// Show detailed snapshot tag information
    Tags {
        /// Show tags for specific game (optional, shows all if not specified)
        #[arg(add = ArgValueCompleter::new(crate::completions::game_name_completion))]
        game_name: Option<String>,
    },
}
