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

#[derive(Parser)]
#[command(
    name = "ecluse",
    version,
    about = "Ephemeral local environments for coding agents — any stack.",
    long_about = None
)]
pub struct Cli {
    #[arg(long, global = true, help = "Enable verbose debug output")]
    pub verbose: bool,

    #[command(subcommand)]
    pub command: Command,
}

#[derive(Subcommand)]
pub enum Command {
    /// Initialize ecluse in the current git repository
    Init(InitArgs),
    /// Create a new isolated worktree session
    Up(UpArgs),
    /// Tear down a session and release its resources
    Down(DownArgs),
    /// List active sessions
    Ls(LsArgs),
    /// Open a shell inside a session's worktree with its env loaded
    Shell(ShellArgs),
    /// Print a session's environment variables (worktree path + all env vars)
    Env(EnvArgs),
    /// Validate .ecluse.toml — check port ranges, service gaps, and search range safety
    Validate(ValidateArgs),
    /// Tear down all active sessions
    Shutdown(ShutdownArgs),
}

#[derive(Args)]
pub struct InitArgs {
    /// Isolation mode (container, host, hybrid)
    #[arg(long, short)]
    pub mode: Option<String>,

    /// Show full signal score breakdown
    #[arg(long)]
    pub explain: bool,

    /// Accept recommended settings without prompting
    #[arg(long, short)]
    pub yes: bool,

    /// Maximum number of concurrent slots
    #[arg(long, default_value = "8")]
    pub max_slots: u8,

    /// Prefix for compose project names and branches
    #[arg(long, default_value = "ecluse")]
    pub prefix: String,

    /// Suppress step output
    #[arg(long)]
    pub quiet: bool,
}

#[derive(Args)]
pub struct UpArgs {
    /// Slug for this session (lowercase letters, numbers, hyphens)
    pub slug: String,

    /// Branch to use (creates ecluse/<slug> from HEAD if not specified)
    #[arg(long)]
    pub branch: Option<String>,

    /// Enable compose watch mode
    #[arg(long)]
    pub watch: bool,

    /// Output session info as JSON (useful for agents)
    #[arg(long)]
    pub json: bool,

    /// Reuse an existing worktree instead of creating a new one
    #[arg(long)]
    pub reuse_worktree: bool,

    /// Override a service port: --port <name>=<value> (repeatable)
    #[arg(long = "port", value_name = "NAME=PORT", value_parser = parse_port_override)]
    pub port_overrides: Vec<(String, u16)>,

    /// Suppress step output (implied by --json)
    #[arg(long)]
    pub quiet: bool,
}

#[derive(Args)]
pub struct DownArgs {
    /// Session slug to tear down
    pub slug: String,

    /// Keep named volumes (do not pass -v to docker compose down)
    #[arg(long)]
    pub keep_volumes: bool,

    /// Keep the git branch after tearing down the worktree (no-op in v0; branches are never deleted)
    #[arg(long)]
    pub keep_branch: bool,

    /// Tear down services but keep the git worktree on disk
    #[arg(long)]
    pub keep_worktree: bool,

    /// Suppress step output
    #[arg(long)]
    pub quiet: bool,
}

fn parse_port_override(s: &str) -> Result<(String, u16), String> {
    let (name, port_str) = s
        .split_once('=')
        .ok_or_else(|| format!("expected NAME=PORT, got '{}'", s))?;
    let port: u16 = port_str
        .parse()
        .map_err(|_| format!("invalid port '{}': must be a number 1-65535", port_str))?;
    if port == 0 {
        return Err("port must be >= 1".into());
    }
    Ok((name.to_string(), port))
}

#[derive(Args)]
pub struct LsArgs {
    /// Output as JSON
    #[arg(long)]
    pub json: bool,
}

#[derive(Args)]
pub struct ShellArgs {
    /// Session slug to enter
    pub slug: String,
}

#[derive(Args)]
pub struct EnvArgs {
    /// Session slug — omit when already inside a worktree
    pub slug: Option<String>,
}

#[derive(Args)]
pub struct ShutdownArgs {
    /// Keep named volumes (do not pass -v to docker compose down)
    #[arg(long)]
    pub keep_volumes: bool,

    /// Tear down services but keep git worktrees on disk
    #[arg(long)]
    pub keep_worktrees: bool,

    /// Suppress step output
    #[arg(long)]
    pub quiet: bool,
}

#[derive(Args)]
pub struct ValidateArgs {
    /// Also print the port allocation table for all slots
    #[arg(long)]
    pub ports: bool,

    /// Suppress step output
    #[arg(long)]
    pub quiet: bool,
}
