const SUBCOMMAND_HELP: Record<string, string> = {
	config: [
		"Usage: sf config",
		"",
		"Re-run the interactive setup wizard to configure:",
		"  - LLM provider (Anthropic, OpenAI, Google, OpenRouter, Ollama, LM Studio, etc.)",
		"  - Web search provider (Brave, Tavily, built-in)",
		"  - Remote questions (Discord, Slack, Telegram)",
		"  - Tool API keys (Context7, Jina, Groq)",
		"",
		"All steps are skippable and can be changed later with /login or /search-provider.",
		"",
		"For detailed provider setup instructions (OpenRouter, Ollama, LM Studio, vLLM,",
		"and other OpenAI-compatible endpoints), see docs/providers.md.",
	].join("\n"),

	update: [
		"Usage: sf update",
		"",
		"Update SF to the latest version.",
		"",
		"Equivalent to: npm install -g singularity-forge@latest",
	].join("\n"),

	sessions: [
		"Usage: sf sessions",
		"       sf sessions --all",
		"",
		"List saved sessions and interactively pick one to resume. Shows date,",
		"message count, and a preview of the first message for each session.",
		"",
		"Sessions are stored per-directory by default. Use --all to list sessions",
		"across all projects.",
		"",
		"  sf sessions        List sessions for the current directory",
		"  sf sessions --all  List sessions across all projects",
		"",
		"Compare with --continue (-c) which always resumes the most recent session.",
	].join("\n"),

	server: [
		"Usage: sf server [start] [path] [--host <host>] [--port <port>]",
		"       sf server stop [path|all]",
		"",
		"Start the full SF operator server for a project.",
		"",
		"The server owns the browser surface and daemon-backed project operations.",
		"sf-server keeps the swarm registry synced from configured scan roots by",
		"default. Set swarms.auto_start=true to also start missing per-repo",
		"autonomous clients.",
		"",
		"Examples:",
		"  sf server",
		"  sf server ~/code/singularity-forge",
		"  sf server start . --host 0.0.0.0 --port 8080",
		"  sf server stop .",
		"  sf server stop all",
	].join("\n"),

	install: [
		"Usage: sf install <source> [-l, --local]",
		"",
		"Install a package/extension source and run post-install validation (dependency checks, setup).",
		"",
		"Examples:",
		"  sf install npm:@foo/bar",
		"  sf install git:github.com/user/repo",
		"  sf install https://github.com/user/repo",
		"  sf install ./local/path",
	].join("\n"),

	remove: [
		"Usage: sf remove <source> [-l, --local]",
		"",
		"Remove an installed package source and its settings entry.",
	].join("\n"),

	list: [
		"Usage: sf list",
		"",
		"List installed package sources from user and project settings.",
	].join("\n"),

	logs: [
		"Usage: sf logs tail|follow [--source notif|session|activity|audit] [--severity level]",
		"",
		"Follow a merged live stream from .sf/notifications.jsonl, the latest",
		"headless session JSONL, the latest .sf/activity JSONL, and .sf/audit-log.jsonl.",
		"",
		"Examples:",
		"  sf logs tail",
		"  sf logs follow --source audit",
		"  sf logs tail --severity error",
	].join("\n"),

	status: [
		"Usage: sf status --live [--watch]",
		"",
		"Show a printable aggregate project view: current milestone, slice, task,",
		"phase, next dispatch, recent events, session cost, and current model.",
		"",
		"Examples:",
		"  sf status --live",
		"  sf status --live --watch",
		"  sf dash --watch",
	].join("\n"),

	dash: ["Usage: sf dash [--watch]", "", "Alias for sf status --live."].join(
		"\n",
	),

	stats: [
		"Usage: sf stats models [--unit-type <type>] [--since <duration>]",
		"",
		"Summarize Bayesian model outcome rows from .sf/sf.db.",
		"",
		"Examples:",
		"  sf stats models --since 7d",
		"  sf stats models --unit-type execute-task --since 24h",
	].join("\n"),

	worktree: [
		"Usage: sf worktree <command> [args]",
		"",
		"Manage isolated git worktrees for parallel work streams.",
		"",
		"Commands:",
		"  list                 List worktrees with status (files changed, commits, dirty)",
		"  merge [name]         Squash-merge a worktree into main and clean up",
		"  clean                Remove all worktrees that have been merged or are empty",
		"  remove <name>        Remove a worktree (--force to remove with unmerged changes)",
		"",
		"The -w flag creates/resumes worktrees for interactive sessions:",
		"  sf -w               Auto-name a new worktree, or resume the only active one",
		"  sf -w my-feature    Create or resume a named worktree",
		"",
		"Lifecycle:",
		"  1. sf -w             Create worktree, start session inside it",
		"  2. (work normally)    All changes happen on the worktree branch",
		"  3. Ctrl+C             Exit — dirty work is auto-committed",
		"  4. sf -w             Resume where you left off",
		"  5. sf worktree merge Squash-merge into main when done",
		"",
		"Examples:",
		"  sf -w                              Start in a new auto-named worktree",
		'  sf -w auth-refactor                Create/resume "auth-refactor" worktree',
		"  sf worktree list                   See all worktrees and their status",
		"  sf worktree merge auth-refactor    Merge and clean up",
		"  sf worktree clean                  Remove all merged/empty worktrees",
		"  sf worktree remove old-branch      Remove a specific worktree",
		"  sf worktree remove old-branch --force  Remove even with unmerged changes",
	].join("\n"),

	graph: [
		"Usage: sf graph <subcommand> [options]",
		"",
		"Manage the SF project knowledge graph. Reads .sf/ artifacts and builds",
		"a queryable graph of milestones, slices, tasks, rules, patterns, and lessons.",
		"",
		"Subcommands:",
		"  build   Parse .sf/ artifacts (STATE.md, milestone ROADMAPs, slice PLANs,",
		"          KNOWLEDGE.md) and write .sf/graphs/graph.json atomically.",
		"  query   Search graph nodes by term (BFS from seed matches, budget-trimmed).",
		"          Returns matching nodes and reachable edges within the token budget.",
		"  status  Show whether graph.json exists, its age, node/edge counts, and",
		"          whether it is stale (built more than 24 hours ago).",
		"  diff    Compare current graph.json with .last-build-snapshot.json.",
		"          Returns added, removed, and changed nodes and edges.",
		"",
		"Examples:",
		"  sf graph build                        Build the graph from .sf/ artifacts",
		"  sf graph status                       Check graph age and node/edge counts",
		'  sf graph query auth                   Find nodes related to "auth"',
		"  sf graph diff                         Show changes since last snapshot",
	].join("\n"),

	plan: [
		"Usage: sf plan <command>",
		"",
		"Manage SF milestone planning artifacts and human docs exports.",
		"",
		"Commands:",
		"  promote <source>     Copy a file from .sf/ to docs/plans/, docs/adr/, or docs/specs/",
		"  list                 List milestone and slice files in .sf/",
		"  diff                 Compare .sf/ state with promoted docs/ artifacts",
		"  specs <cmd>          Generate, diff, or check docs/specs exports from .sf state",
		"",
		"See docs/plans/README.md, docs/adr/README.md, and docs/specs/README.md for conventions.",
	].join("\n"),

	schedule: [
		"Usage: sf schedule <command> [args]",
		"",
		"Manage time-bound reminders and deferred work items.",
		"Entries are stored as versioned append-only JSONL in .sf/schedule.jsonl (project)",
		"or ~/.sf/schedule.jsonl (global). No daemon required — items surface on pull.",
		"",
		"Commands:",
		"  add   --in <duration> [--kind <kind>] [--scope <scope>] <title>",
		"         --at <ISO-date>  Schedule by absolute date instead",
		"  list  [--due] [--all] [--json] [--scope <scope>]",
		"  done  <id>             Mark a scheduled item as done",
		"  cancel <id>            Cancel a scheduled item",
		"  snooze <id> --by <duration>   Postpone by relative time",
		"  run   <id>            Execute a scheduled item (show reminder or run command)",
		"",
		"Duration format: <number><unit> where unit is w(weeks), d(days), h(hours), m(minutes).",
		"                  e.g. 30m, 4h, 2d, 1w",
		"",
		"Scope: project (default, stored in .sf/schedule.jsonl) or global (~/.sf/schedule.jsonl).",
		"",
		"Kinds: reminder, milestone_check, review_due, review, audit, recurring, command",
		"",
		"Examples:",
		'  sf schedule add --in 2w "Review feature adoption metrics"',
		'  sf schedule add --at 2026-06-01T09:00:00Z --kind audit "Audit ADR-007"',
		"  sf schedule list --due",
		"  sf schedule snooze 01ARZ3ND --by 1d",
		"  sf schedule done 01ARZ3ND",
	].join("\n"),

	key: [
		"Usage: sf key <subcommand> [args]",
		"",
		"Manage provider API keys stored in ~/.sf/agent/auth.json.",
		"",
		"Credentials for SF runtime live in ~/.sf/agent/auth.json.",
		"SF does NOT read API keys from environment variables at runtime —",
		"env is only used during initial provider setup. Use `sf key set`",
		"to rotate keys. auth.json is always the authoritative source.",
		"",
		"Subcommands:",
		"  set <provider> <api-key>   Set or rotate the API key for a provider",
		"  get <provider>             Show key status (last 4 chars only, never full key)",
		"  remove <provider> [--yes]  Remove the credential (prompts unless --yes)",
		"  list                       List all providers with credential status",
		"",
		"Examples:",
		"  sf key set anthropic sk-ant-abc123        Set the Anthropic API key",
		"  sf key set xiaomi tp-abc123               Set the Xiaomi API key",
		"  sf key get anthropic                      Show masked key for anthropic",
		"  sf key remove anthropic                   Remove anthropic credential (confirms)",
		"  sf key remove anthropic --yes             Remove without prompting",
		"  sf key list                               List all providers",
		"",
		"Security:",
		"  - Keys are never echoed in full. Only the last 4 characters are shown.",
		"  - All writes go through AuthStorage (file-locked, chmod 600).",
		"  - sf key remove always asks for confirmation unless --yes is passed.",
	].join("\n"),

	headless: [
		"Usage: sf headless [flags] [command] [args...]",
		"",
		"Machine surface for direct SF commands. Runs the same SF flow without rendering the TUI.",
		"",
		"Flags:",
		"  --timeout N            Overall timeout in ms (default: 300000)",
		"  --json                 JSONL event stream to stdout (alias for --output-format stream-json)",
		"  --output-format <fmt>  Output format: text (default), json (structured result), stream-json (JSONL events)",
		"  --bare                 Minimal context: skip CLAUDE.md, AGENTS.md, user settings, user skills",
		"  --resume <id>          Resume a prior headless session by ID",
		"  --model ID             Override model",
		"  --supervised           Forward interactive UI requests to orchestrator via stdout/stdin",
		"  --response-timeout N   Timeout (ms) for orchestrator response (default: 30000)",
		"  --answers <path>       Pre-supply answers and secrets (JSON file)",
		"  --events <types>       Filter JSONL output to specific event types (comma-separated)",
		"",
		"Commands:",
		"  autonomous           Run all queued product units continuously",
		"  next                 Run one unit",
		"  status               Show progress dashboard",
		"  new-milestone        Create a milestone from a specification document",
		"  query                Machine snapshot: JSON state + next dispatch + costs (no LLM)",
		"  usage                Live LLM-provider usage snapshot (today: gemini-cli tier + per-model quota)",
		"  reflect              Assemble reflection corpus + render prompt for cross-corpus pattern analysis (--json for raw, --run to dispatch to gemini-cli, --model <id> to override)",
		"  triage               Render canonical self-feedback triage prompt (--list/--json inspect, --run writes decisions, --apply runs triage-decider -> review-code)",
		"  complete-slice       Mark a slice complete out-of-band: complete-slice <M>/<S> [--reason <txt>]",
		"  skip-slice           Mark a slice skipped out-of-band (placeholder/migration cleanup)",
		"  complete-milestone   Mark a milestone complete out-of-band: complete-milestone <M> [--reason <txt>]",
		"  feedback add         File a self_feedback entry (--summary <txt> --severity low|medium|high|critical [--kind <k>] [--evidence <t>] [--suggested-fix <t>] [--milestone M --slice S --task T] [--impact-score N] [--effort-estimate N] [--blocking] [--purpose <fragment>])",
		"  feedback list        List self_feedback entries [--unresolved] [--severity <s>] [--purpose <fragment>] [--json]",
		"  feedback resolve     Resolve an entry: feedback resolve <id> --reason <txt> [--evidence-kind human-clear|agent-fix|...]",
		"",
		"new-milestone flags:",
		"  --context <path>     Path to spec/PRD file (use '-' for stdin)",
		"  --context-text <txt> Inline specification text",
		"  --autonomous         Start autonomous mode after milestone creation",
		"  --verbose            Show tool calls in progress output",
		"  --skip-pdd-check     Bypass the ADR-0000 PDD-fields gate (migration escape hatch)",
		"",
		"Output formats:",
		"  text         Human-readable progress on stderr (default)",
		"  json         Collect events silently, emit one structured result on stdout at exit",
		"  stream-json  Stream JSONL events to stdout in real time (same as --json)",
		"",
		"Examples:",
		"  sf headless                                    Show this help",
		"  sf headless autonomous                         Run autonomous mode through the machine surface",
		"  sf headless next                               Run one unit",
		"  sf headless --output-format json autonomous    Structured JSON result on stdout",
		"  sf headless --json status                      Machine-readable JSONL stream",
		"  sf headless --timeout 60000 autonomous         Run autonomous with 1-minute timeout",
		"  sf headless --bare autonomous                  Minimal context (CI/ecosystem use)",
		"  sf headless --resume abc123 autonomous         Resume a prior session",
		"  sf headless new-milestone --context spec.md    Create milestone from file",
		"  cat spec.md | sf headless new-milestone --context -   From stdin",
		"  sf headless new-milestone --context spec.md --autonomous    Create + run autonomously",
		"  sf headless --supervised autonomous               Supervised orchestrator mode",
		"  sf headless --answers answers.json autonomous     With pre-supplied answers",
		"  sf headless --events agent_end,extension_ui_request autonomous   Filtered event stream",
		"  sf headless query                              Instant machine JSON state snapshot",
		"  sf headless status uok                        UOK gate health table (last 24h)",
		"  sf headless status uok --json                 UOK gate health as JSON",
		"  sf headless triage --list                      Self-feedback queue digest (impact↓ effort↑ ts↑)",
		"  sf headless triage | sf-some-model             Pipe triage prompt to any model",
		"  sf headless triage --run                       Dispatch triage to default model + write decisions",
		"  sf headless triage --apply                     Apply via triage-decider, then gate with review-code",
		"  sf headless reflect                            Render reflection prompt for piping",
		"  sf headless reflect --run                      Dispatch reflection + write report",
		"  sf headless complete-slice M010/S03            Flip M010/S03 to status=complete (idempotent)",
		'  sf headless skip-slice M003/S01 --reason "migration placeholder"   Mark placeholder slice skipped',
		"  sf headless complete-milestone M010            Flip milestone to status=complete",
		'  sf headless feedback add --severity high --summary "30K truncate drops the why"   File self-feedback',
		'  sf headless feedback add --summary "..." --purpose "M015 vision: ..."   Anchor to a purpose (ADR-0000)',
		"  sf headless feedback list --unresolved         Pending self-feedback entries",
		'  sf headless feedback list --purpose "M015 vision"   Triage by purpose anchor',
		'  sf headless feedback resolve sf-mp4xxx --reason "shipped in 7b85a6"   Resolve an entry',
		"",
		"Exit codes: 0 = success, 1 = error/timeout, 10 = blocked, 11 = cancelled",
	].join("\n"),
};

// Alias: `sf wt --help` → same as `sf worktree --help`
SUBCOMMAND_HELP["wt"] = SUBCOMMAND_HELP["worktree"];

export function printHelp(version: string): void {
	process.stdout.write(`SF v${version} — Singularity Forge\n\n`);
	process.stdout.write("Usage: sf [options] [message...]\n\n");
	process.stdout.write("Options:\n");
	process.stdout.write(
		"  --mode <text|json|rpc>     Session I/O mode: text/json print format or RPC protocol\n",
	);
	process.stdout.write("  --print, -p              Single-shot print mode\n");
	process.stdout.write(
		"  --continue, -c           Resume the most recent session\n",
	);
	process.stdout.write(
		"  --worktree, -w [name]    Start in an isolated worktree (auto-named if omitted)\n",
	);
	process.stdout.write(
		"  --model <id>             Override model (e.g. provider/model-id)\n",
	);
	process.stdout.write(
		"  --no-session             Disable session persistence\n",
	);
	process.stdout.write(
		"  --extension <path>       Load additional extension\n",
	);
	process.stdout.write("  --tools <a,b,c>          Restrict available tools\n");
	process.stdout.write(
		"  --list-models [search]   List available models and exit\n",
	);
	process.stdout.write(
		"  --discover               Force live verification for filtered --list-models\n",
	);
	process.stdout.write("  --version, -v            Print version and exit\n");
	process.stdout.write("  --help, -h               Print this help and exit\n");
	process.stdout.write("\nSubcommands:\n");
	process.stdout.write("  config                   Re-run the setup wizard\n");
	process.stdout.write(
		"  install <source>         Install a package/extension source\n",
	);
	process.stdout.write(
		"  remove <source>          Remove an installed package source\n",
	);
	process.stdout.write(
		"  list                     List installed package sources\n",
	);
	process.stdout.write(
		"  update                   Update SF to the latest version\n",
	);
	process.stdout.write(
		"  sessions                 List and resume a past session\n",
	);
	process.stdout.write(
		"  server [path]            Start the full SF operator server\n",
	);
	process.stdout.write("  logs tail|follow         Follow merged SF logs\n");
	process.stdout.write(
		"  status --live            Show aggregate project status\n",
	);
	process.stdout.write("  dash                     Alias for status --live\n");
	process.stdout.write("  stats models             Summarize model outcomes\n");
	process.stdout.write(
		"  worktree <cmd>           Manage worktrees (list, merge, clean, remove)\n",
	);
	process.stdout.write(
		"  autonomous [args]        Run autonomous mode through the machine surface (pipeable)\n",
	);
	process.stdout.write(
		"  headless [cmd] [args]    Machine surface for direct SF commands\n",
	);
	process.stdout.write(
		"  graph <subcommand>       Manage knowledge graph (build, query, status, diff)\n",
	);
	process.stdout.write(
		"  plan <cmd>               Manage SF planning artifacts and docs exports\n",
	);
	process.stdout.write(
		"  schedule <cmd>          Manage time-bound reminders (add, list, done, cancel, snooze, run)\n",
	);
	process.stdout.write(
		"  key <set|get|remove|list>  Manage provider API keys in auth.json\n",
	);
	process.stdout.write(
		"\nRun sf <subcommand> --help for subcommand-specific help.\n",
	);
}

export function printSubcommandHelp(
	subcommand: string,
	version: string,
): boolean {
	const help = SUBCOMMAND_HELP[subcommand];
	if (!help) return false;
	process.stdout.write(`SF v${version} — Singularity Forge\n\n`);
	process.stdout.write(help + "\n");
	return true;
}
