# reflection/nulib/interactive.nu — Interactive command picker and group routing.
# Provides the "?" selector, missing-target handler, and run-group-command dispatch.

use ../modules/describe.nu *
use ../modules/config.nu *
use ../modules/sync.nu *
use ../modules/coder.nu *
use ../modules/manifest.nu *
use ../modules/backlog.nu *
use ../modules/adr.nu *

use ./help.nu [help-group]

export def group-command-info [group: string]: nothing -> list<record> {
  match $group {
    "describe" => [
      { name: project,      desc: "philosophy, axioms, state, gates",        args: [] },
      { name: capabilities, desc: "just modules, modes, commands, .claude",  args: [] },
      { name: constraints,  desc: "invariants, Hard constraints, gates",     args: [] },
      { name: tools,        desc: "dev tools, CI tools, just recipes",       args: [] },
      { name: features,     desc: "project features list or detail",         args: [{name: "id", prompt: "feature id (empty=list all)", optional: true}] },
      { name: impact,       desc: "if I change X, what's affected?",         args: [{name: "node_id", prompt: "node id", optional: false}] },
      { name: why,          desc: "why does X exist?",                       args: [{name: "id", prompt: "node/adr id", optional: false}] },
    ],
    "backlog" => [
      { name: roadmap,  desc: "state dimensions + open items by priority", args: [] },
      { name: list,     desc: "open backlog items",                        args: [] },
      { name: show,     desc: "show full backlog item",                    args: [{name: "id", prompt: "item id", optional: false}] },
      { name: add,      desc: "create new backlog item",                   args: [{name: "title", prompt: "title", optional: false}] },
      { name: done,     desc: "mark item as done",                         args: [{name: "id", prompt: "item id", optional: false}] },
      { name: cancel,   desc: "cancel item",                               args: [{name: "id", prompt: "item id", optional: false}] },
      { name: promote,  desc: "promote item priority",                     args: [{name: "id", prompt: "item id", optional: false}] },
    ],
    "config" => [
      { name: show,     desc: "display config profile",                    args: [{name: "profile", prompt: "profile name", optional: false}] },
      { name: history,  desc: "config change history",                     args: [{name: "profile", prompt: "profile name", optional: false}] },
      { name: diff,     desc: "diff between profiles or versions",         args: [{name: "profile", prompt: "profile name", optional: false}, {name: "from_id", prompt: "from id", optional: false}, {name: "to_id", prompt: "to id", optional: false}] },
      { name: verify,   desc: "verify profile integrity",                  args: [{name: "profile", prompt: "profile name", optional: false}] },
      { name: audit,    desc: "full config audit",                         args: [] },
      { name: apply,    desc: "apply config profile",                      args: [{name: "profile", prompt: "profile name", optional: false}] },
      { name: rollback, desc: "rollback to previous config",               args: [{name: "profile", prompt: "profile name", optional: false}, {name: "to_id", prompt: "target id", optional: false}] },
    ],
    "sync" => [
      { name: scan,    desc: "analyze project artifacts",                  args: [] },
      { name: diff,    desc: "compare scan vs ontology",                   args: [] },
      { name: propose, desc: "generate NCL patches for drift",             args: [] },
      { name: apply,   desc: "apply proposed changes with confirmation",   args: [] },
      { name: state,   desc: "sync state.ncl dimensions",                 args: [] },
      { name: audit,   desc: "full ontology↔code audit",                  args: [] },
      { name: watch,   desc: "continuous drift monitoring",                args: [] },
    ],
    "coder" => [
      { name: authors,  desc: "list registered authors",                   args: [] },
      { name: init,     desc: "initialize author workspace",               args: [{name: "author", prompt: "author name", optional: false}] },
      { name: record,   desc: "record structured entry",                   args: [{name: "author", prompt: "author name", optional: false}, {name: "title", prompt: "title", optional: false}, {name: "content", prompt: "content", optional: false}] },
      { name: log,      desc: "query recorded entries",                    args: [] },
      { name: export,   desc: "export entries (json/jsonl/csv)",           args: [] },
      { name: triage,   desc: "classify inbox markdown",                   args: [{name: "author", prompt: "author name", optional: false}] },
      { name: ls,       desc: "list files in author workspace",            args: [{name: "author", prompt: "author name (empty=all)", optional: true}] },
      { name: search,   desc: "search across entries",                     args: [{name: "pattern", prompt: "search pattern", optional: false}] },
      { name: publish,  desc: "promote entries to general/",               args: [{name: "author", prompt: "author name", optional: false}, {name: "category", prompt: "category", optional: false}] },
      { name: graduate, desc: "copy to committed knowledge path",          args: [{name: "source", prompt: "source category", optional: false}] },
    ],
    "manifest" => [
      { name: mode,      desc: "activate operational mode",                args: [{name: "id", prompt: "mode id", optional: false}] },
      { name: publish,   desc: "publish artifact to registry",             args: [{name: "id", prompt: "service id", optional: false}] },
      { name: layers,    desc: "show manifest layers",                     args: [] },
      { name: consumers, desc: "show consumption modes",                   args: [] },
    ],
    "adr" => [
      { name: list,     desc: "list all ADRs with status",                 args: [] },
      { name: validate, desc: "run Hard constraint checks",                args: [] },
      { name: accept,   desc: "Proposed → Accepted",                      args: [{name: "id", prompt: "adr id (e.g. adr-001)", optional: false}] },
      { name: show,     desc: "show ADR detail",                          args: [{name: "id", prompt: "adr id (empty=interactive)", optional: true}] },
    ],
    "migrate" => [
      { name: list,    desc: "all migrations with applied/pending status", args: [] },
      { name: pending, desc: "only pending migrations",                    args: [] },
      { name: show,    desc: "instructions for a specific migration",      args: [{name: "id", prompt: "migration id (e.g. 0001)", optional: false}] },
    ],
    _ => [],
  }
}

export def group-subcommands [group: string]: nothing -> list<string> {
  group-command-info $group | get name | each { |n| $n | into string }
}

export def run-interactive [group: string] {
  let cmds = (group-command-info $group)
  if ($cmds | is-empty) {
    help-group $group
    return
  }
  let labels = ($cmds | each { |c|
    let n = ($c.name | into string)
    let pad_width = ([(16 - ($n | str length)), 0] | math max)
    let pad = (" " | fill -w $pad_width -c ' ')
    $"($n)($pad)($c.desc)"
  })
  let picked_label = ($labels | input list $"(ansi cyan_bold)($group):(ansi reset) ")
  if ($picked_label | is-empty) { return }
  let idx = ($labels | enumerate | where { |e| $e.item == $picked_label } | first | get index)
  let cmd_info = ($cmds | get $idx)
  let sub = ($cmd_info.name | into string)
  print $"  (ansi dark_gray)($cmd_info.desc)(ansi reset)"
  mut collected_args: list<string> = []
  for arg in $cmd_info.args {
    let val = try {
      input $"  (ansi cyan)($arg.prompt):(ansi reset) "
    } catch { |err|
      if ($err.msg | str contains "interrupted") {
        print $"\n  (ansi yellow)cancelled(ansi reset)"
        return
      }
      error make { msg: $err.msg }
    }
    if ($val | is-empty) and (not $arg.optional) {
      print $"  (ansi yellow)required(ansi reset)"
      return
    }
    $collected_args = ($collected_args | append $val)
  }
  print ""
  let result = (run-group-command $group $sub $collected_args)
  if ($result | describe) != "nothing" { print $result }
}

export def run-group-command [group: string, sub: string, args: list<string>] {
  let a0 = ($args | get -o 0 | default "")
  let a1 = ($args | get -o 1 | default "")
  let a2 = ($args | get -o 2 | default "")
  match $group {
    "describe" => {
      match $sub {
        "project"      => { describe project },
        "capabilities" => { describe capabilities },
        "constraints"  => { describe constraints },
        "tools"        => { describe tools },
        "features"     => { if ($a0 | is-empty) { describe features } else { describe features $a0 } },
        "impact"       => { describe impact $a0 },
        "why"          => { describe why $a0 },
        _ => {},
      }
    },
    "backlog" => {
      match $sub {
        "roadmap" => { backlog roadmap },
        "list"    => { backlog list },
        "show"    => { backlog show $a0 },
        "add"     => { backlog add $a0 },
        "done"    => { backlog done $a0 },
        "cancel"  => { backlog cancel $a0 },
        "promote" => { backlog promote $a0 },
        _ => {},
      }
    },
    "config" => {
      match $sub {
        "show"     => { config show $a0 },
        "history"  => { config history $a0 },
        "diff"     => { config diff $a0 $a1 $a2 },
        "verify"   => { config verify $a0 },
        "audit"    => { config audit },
        "apply"    => { config apply $a0 },
        "rollback" => { config rollback $a0 $a1 },
        _ => {},
      }
    },
    "sync" => {
      match $sub {
        "scan"    => { sync scan },
        "diff"    => { sync diff },
        "propose" => { sync propose },
        "apply"   => { sync apply },
        "state"   => { sync state },
        "audit"   => { sync audit },
        "watch"   => { sync watch },
        _ => {},
      }
    },
    "coder" => {
      match $sub {
        "authors"  => { coder authors },
        "init"     => { coder init $a0 },
        "record"   => { coder record $a0 --title $a1 $a2 },
        "log"      => { coder log },
        "export"   => { coder export },
        "triage"   => { coder triage $a0 },
        "ls"       => { if ($a0 | is-empty) { coder ls } else { coder ls $a0 } },
        "search"   => { coder search $a0 },
        "publish"  => { coder publish $a0 $a1 },
        "graduate" => { coder graduate $a0 },
        _ => {},
      }
    },
    "manifest" => {
      match $sub {
        "mode"      => { manifest mode $a0 },
        "publish"   => { manifest publish $a0 },
        "layers"    => { manifest layers },
        "consumers" => { manifest consumers },
        _ => {},
      }
    },
    "adr" => {
      match $sub {
        "list"     => { adr list },
        "validate" => { adr validate },
        "accept"   => { adr accept $a0 },
        "show"     => { if ($a0 | is-empty) { adr show --interactive } else { adr show $a0 } },
        _ => {},
      }
    },
    "migrate" => {
      match $sub {
        "list"    => { migrate list },
        "pending" => { migrate pending },
        "show"    => { migrate show $a0 },
        _ => {},
      }
    },
    _ => {},
  }
}

export def missing-target [group: string, action?: string] {
  let act = ($action | default "")
  if $act == "h" or $act == "help" {
    help-group $group
    return
  }
  if $act == "?" or $act == "select" or $act == "" {
    run-interactive $group
    return
  }
  let cmd = ($env.ONTOREF_CALLER? | default "ontoref")
  print $"  (ansi yellow)($group)(ansi reset): unknown subcommand '($act)'. Run '(ansi green)($cmd) ($group) h(ansi reset)' for options."
}
