use clap::{Parser, Subcommand, ValueEnum};

use crate::tools::Tool;

/// Where to apply permission grants declared by a package.
#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
#[clap(rename_all = "lowercase")]
pub enum PermissionScope {
    /// Write to the user-level settings file (e.g. `~/.claude/settings.json`).
    Global,
    /// Write to the project-level settings file (e.g. `.claude/settings.json`).
    Project,
    /// Skip applying permissions entirely.
    Skip,
}

/// For project-scope grants, which file in `.claude/` receives the rules.
#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
#[clap(rename_all = "lowercase")]
pub enum PermissionFile {
    /// `.claude/settings.local.json` — gitignored, personal.
    Local,
    /// `.claude/settings.json` — checked-in project policy.
    Shared,
}

#[derive(Debug, Default, Clone, clap::Args)]
pub struct PermissionFlags {
    /// Where to apply package permission grants. Defaults to the install scope
    /// (a project install offers a prompt; `-y` accepts the default).
    #[arg(long = "permissions", value_enum)]
    pub scope: Option<PermissionScope>,
    /// For project-scope grants, which `.claude/settings*.json` file to write
    /// (defaults to `shared`).
    #[arg(long = "permissions-file", value_enum)]
    pub file: Option<PermissionFile>,
}

const TOP_EXAMPLES: &str = "\
Examples:
  aimgr                           # interactive picker
  aimgr init                      # wizard: write .aimgr/aimgr.toml and sync
  aimgr install                   # pick tools to install (interactive)
  aimgr install --all             # install every tool declared in global config
  aimgr install claude            # install the claude CLI + add to global intent
  aimgr install my-tool           # scaffold a custom tool definition
  aimgr uninstall claude          # run the registered uninstaller
  aimgr use                       # pick packages to install (interactive)
  aimgr use --all                 # install every package declared in global config
  aimgr use seek                  # add + install + wire into this project
  aimgr use -g claude-mem         # add to global config
  aimgr unuse seek                # remove from this project
  aimgr sync                      # reconcile current project (or pick one)
  aimgr sync --all                # reconcile every managed project
  aimgr sync --global             # install everything declared in global config
  aimgr up                        # update every installed tool + package
  aimgr purge seek                # remove everywhere + run uninstaller
  aimgr ls                        # what's installed here + globally
  aimgr registry                  # every tool + package aimgr knows
  aimgr info seek                 # registry details for a tool or package
  aimgr edit                      # $EDITOR on global config
  aimgr edit seek                 # $EDITOR on the package (forks built-ins)
  aimgr implode                   # nuke all aimgr config/state";

#[derive(Debug, Parser)]
#[command(
    name = "aimgr",
    version,
    about = "AI tool config manager — use/unuse packages across projects.",
    after_help = TOP_EXAMPLES,
)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Option<Command>,
}

#[derive(Debug, Subcommand)]
pub enum Command {
    /// Wizard — create `.aimgr/aimgr.toml` and sync.
    Init,

    /// Add a package (to project by default; `-g` for global). With a name, `--all`
    /// applies to every managed project. With no name → interactive picker, or
    /// `--all` installs every package declared in `~/.config/aimgr/config.toml`
    /// (inside a managed project it prompts whether to also wire them into the project).
    Use {
        name: Option<String>,
        #[command(flatten)]
        scope: ScopeFlags,
        /// Pick a specific install method by id (e.g. `curl`, `go`).
        #[arg(long)]
        method: Option<String>,
        /// Trust/accept all prompts (auto-approve trust gate, skip reinstall prompt, default to global scope).
        #[arg(long, short = 'y')]
        yes: bool,
        #[command(flatten)]
        permissions: PermissionFlags,
    },

    /// Remove a package from a scope's manifest and unwire it there.
    /// Defaults to the current project; `-g` removes from the global overlay;
    /// `--all` removes from every managed project.
    Unuse {
        name: String,
        #[command(flatten)]
        scope: ScopeFlags,
    },

    /// Reconcile intent (manifest) against reality (state). Defaults to the current
    /// project, or a picker over managed projects if cwd is outside one. `--all`
    /// reconciles every managed project. `--global` installs every tool + package
    /// declared in `~/.config/aimgr/config.toml` (project-scope packages are skipped).
    /// `--force` overwrites hand-edited blocks without prompting.
    Sync {
        /// Reconcile every managed project.
        #[arg(long)]
        all: bool,
        /// Install everything declared in the global `config.toml`.
        #[arg(long)]
        global: bool,
        /// Overwrite hand-edited blocks without prompting.
        #[arg(long)]
        force: bool,
        /// Trust/accept all prompts (auto-approve trust gate).
        #[arg(long, short = 'y')]
        yes: bool,
    },

    /// Update every installed tool + package in parallel (mise-style progress UI). Pass a name to update one.
    Up {
        /// Only update this tool or package.
        name: Option<String>,
    },

    /// Remove everywhere (project + global + machine state) and run the package's
    /// uninstaller. Prompts before destructive steps; pass `--yes` to skip prompts.
    Purge {
        name: String,
        /// Skip confirmation prompts.
        #[arg(long)]
        yes: bool,
    },

    /// Show what's in use here, plus the global overlay.
    Status,

    /// Flat table of installed tools and packages.
    Ls,

    /// List every tool + package aimgr knows about (built-in + custom).
    Registry,

    /// Show registry details for a tool or package (description, homepage, install methods, …).
    Info { name: String },

    /// Install AI tool runtimes. With no name → interactive picker (tools not yet
    /// installed; offers reinstall when everything is already installed). With a
    /// name → install one tool (and add it to the global intent if it has a runtime).
    /// `--all` installs every tool declared in `~/.config/aimgr/config.toml`; inside
    /// a managed project it prompts whether to also record them in the project intent.
    Install {
        name: Option<String>,
        /// Install every tool declared in the global config (prompts for scope in a project).
        #[arg(long)]
        all: bool,
        /// Trust/accept all prompts (auto-approve trust gate, skip reinstall prompt, default to global scope).
        #[arg(long, short = 'y')]
        yes: bool,
    },

    /// Uninstall an AI tool runtime (runs the registered uninstaller). For packages,
    /// use `unuse`/`purge`. Pass `--yes` to skip confirmation prompts.
    Uninstall {
        name: String,
        /// Skip confirmation prompts.
        #[arg(long)]
        yes: bool,
    },

    /// Open $EDITOR on the global config, or on a specific tool/package (forks built-ins to custom first).
    Edit { name: Option<String> },

    /// Remove all aimgr config + state on this machine. Prompts before deleting;
    /// pass `--yes` to skip the prompt.
    Implode {
        /// Skip confirmation prompt.
        #[arg(long)]
        yes: bool,
    },

    /// Inverse of `init` — unwire managed blocks, delete `.aimgr/`, deregister the
    /// project. Prompts before deleting; pass `--yes` to skip the prompt.
    Deinit {
        /// Skip confirmation prompt.
        #[arg(long)]
        yes: bool,
    },
}

#[derive(Debug, Default, Clone, clap::Args)]
pub struct ScopeFlags {
    /// Global (write to `~/.config/aimgr/config.toml`).
    #[arg(long, short = 'g')]
    pub global: bool,
    /// Apply to every managed project.
    #[arg(long)]
    pub all: bool,
    /// Restrict to specific tools (defaults to every tool in the manifest).
    #[arg(long, value_enum)]
    pub tool: Vec<Tool>,
}
