//! Command-line surface (plan §3). Provider/model/wiki-dir are global so they
//! can appear before or after the subcommand.

use crate::config::ProviderId;
use clap::{Args, Parser, Subcommand};
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[command(
    name = "hephaes",
    version,
    about = "Build and maintain a Karpathy-style LLM wiki for a code repository.",
    long_about = "hephaes deeply reads a repository, builds a persistent interlinked wiki/ \
                  of markdown, keeps it current, and answers questions against it."
)]
pub struct Cli {
    #[command(flatten)]
    pub global: GlobalArgs,

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

#[derive(Args, Debug, Clone, Default)]
pub struct GlobalArgs {
    /// Model provider backend to use for this run.
    #[arg(long, global = true, value_enum)]
    pub provider: Option<ProviderId>,

    /// Model id (provider-specific). Omit to use the provider/CLI default.
    #[arg(long, global = true)]
    pub model: Option<String>,

    /// Wiki output directory (default: ./wiki).
    #[arg(long = "wiki-dir", global = true)]
    pub wiki_dir: Option<String>,

    /// Max concurrent page builds (reserved; sequential in v1).
    #[arg(long, global = true)]
    pub concurrency: Option<usize>,

    /// Show every tool call as the agent works.
    #[arg(short = 'v', long, global = true)]
    pub verbose: bool,

    /// Suppress progress output; print only the final summary.
    #[arg(short = 'q', long, global = true)]
    pub quiet: bool,
}

#[derive(Subcommand, Debug)]
pub enum Command {
    /// Cold-start: scan the repo, plan structure, and build wiki/.
    Init(InitArgs),
    /// Incremental: re-ingest changed files and update affected pages.
    Update(UpdateArgs),
    /// Ask a question against the wiki (cited answer).
    Ask(AskArgs),
    /// Health-check the wiki (broken links, orphans, drift, contradictions).
    Lint(LintArgs),
    /// Show configuration, wiki, and drift status.
    Status(StatusArgs),
    /// View or change configuration.
    Config(ConfigArgs),
    /// List provider backends and their auth status.
    Providers,
    /// Configure a provider / store its API key (re-runs the selector).
    Login(LoginArgs),
    /// Run an MCP server over stdio (expose the wiki to MCP clients).
    #[cfg(feature = "mcp")]
    Mcp(McpArgs),
    /// Serve a local web app for browsing the wiki and asking questions.
    #[cfg(feature = "web")]
    Serve(ServeArgs),
}

#[derive(Args, Debug)]
#[cfg(feature = "web")]
pub struct ServeArgs {
    /// Repository path (default: current directory).
    pub path: Option<PathBuf>,
    /// Bind host (non-loopback requires --token).
    #[arg(long, default_value = "127.0.0.1")]
    pub host: String,
    /// Bind port.
    #[arg(long, default_value_t = 7878)]
    pub port: u16,
    /// Access token required for non-loopback binds.
    #[arg(long)]
    pub token: Option<String>,
}

#[derive(Args, Debug)]
#[cfg(feature = "mcp")]
pub struct McpArgs {
    /// Repository path (default: current directory).
    pub path: Option<PathBuf>,
    /// Allow mutating tools (e.g. update). Off by default (read-only).
    #[arg(long)]
    pub allow_write: bool,
}

#[derive(Args, Debug)]
pub struct InitArgs {
    /// Repository path (default: current directory).
    pub path: Option<PathBuf>,
    /// Print the planned scope and exit without writing anything.
    #[arg(long)]
    pub dry_run: bool,
    /// Pause for approval at the plan stage (default: fully autonomous).
    #[arg(long)]
    pub interactive: bool,
    /// git-commit the wiki after building.
    #[arg(long)]
    pub commit: bool,
    /// Extra include globs (relative to repo root).
    #[arg(long)]
    pub include: Vec<String>,
    /// Extra exclude globs (relative to repo root).
    #[arg(long)]
    pub exclude: Vec<String>,
    /// Skip files larger than this many bytes.
    #[arg(long)]
    pub max_file_bytes: Option<u64>,
}

#[derive(Args, Debug)]
pub struct UpdateArgs {
    /// Repository path (default: current directory).
    pub path: Option<PathBuf>,
    /// git-commit the wiki after updating.
    #[arg(long)]
    pub commit: bool,
    /// Pause for approval before applying updates.
    #[arg(long)]
    pub interactive: bool,
}

#[derive(Args, Debug)]
pub struct AskArgs {
    /// The question (quoting optional).
    #[arg(trailing_var_arg = true, allow_hyphen_values = true, required = true)]
    pub prompt: Vec<String>,
    /// File the answer back into the wiki as a new page.
    #[arg(long)]
    pub save: bool,
    /// Allow reading source files when the wiki is insufficient.
    #[arg(long)]
    pub from_source: bool,
}

#[derive(Args, Debug)]
pub struct LintArgs {
    /// Also run an LLM pass for contradictions/stale-claim analysis.
    #[arg(long)]
    pub deep: bool,
}

#[derive(Args, Debug)]
pub struct StatusArgs {
    /// Repository path (default: current directory).
    pub path: Option<PathBuf>,
}

#[derive(Args, Debug)]
pub struct ConfigArgs {
    #[command(subcommand)]
    pub action: Option<ConfigAction>,
}

#[derive(Subcommand, Debug)]
pub enum ConfigAction {
    /// Print the resolved configuration and its sources (default).
    Show,
    /// Set a config key in the project .hephaes/config.toml.
    Set { key: String, value: String },
    /// Print the path of the project config file.
    Path,
}

#[derive(Args, Debug)]
pub struct LoginArgs {
    /// Provider to configure (omit to pick interactively).
    #[arg(value_enum)]
    pub provider: Option<ProviderId>,
}
