#!/usr/bin/env nu
# Private dev-internal overlay manager.
#
# Tracks the gitignored .coder/ and .claude/ of a project in a SEPARATE
# "bare-overlay" repo: its git-dir lives apart (<worktree>/.internal.git, itself
# gitignored), its work-tree is the project root, and it tracks only the two
# private dirs. The public repo and the overlay coexist on one working tree
# without colliding (distinct git-dirs). The overlay pushes ONLY to a private
# remote and is NEVER mirrored — same boundary as vault (ADR-062).
#
# Generic: works for any project using the same .coder/.claude layout.
#
# Usage:
#   nu internal-overlay.nu setup   <worktree> [--remote <forgejo-priv-url>] [--push]
#   nu internal-overlay.nu onboard <worktree> --remote <forgejo-priv-url>
#   nu internal-overlay.nu run     <worktree> -- <git args...>
#   nu internal-overlay.nu status  <worktree>

# Absolute path of the overlay's bare git-dir for a given work-tree.
def overlay-gitdir [wt: path] {
  $wt | path join ".internal.git"
}

# The git CLI prefix (cwd into the work-tree, pin git-dir + work-tree).
def git-prefix [wt: path] {
  ["-C" $wt "--git-dir" (overlay-gitdir $wt) "--work-tree" $wt]
}

# Resolve the overlay work-tree for daily commands (commit/run/status), in order:
#   1. explicit --worktree flag
#   2. $env.ONTOREF_INTERNAL_ROOT  (for agents in a jj workspace — anchors the
#      overlay to the MAIN checkout, since ignored .coder/.claude are NOT
#      materialized in a fresh workspace)
#   3. walk up from $env.PWD to the nearest .internal.git
# The overlay must already exist (setup/onboard create it).
def resolve-wt [given: string] {
  if ($given | is-not-empty) { return ($given | path expand) }
  let er = ($env.ONTOREF_INTERNAL_ROOT? | default "")
  if ($er | is-not-empty) {
    let p = ($er | path expand)
    if not (overlay-gitdir $p | path exists) {
      print --stderr $"ONTOREF_INTERNAL_ROOT=($p) but no overlay at (overlay-gitdir $p)"
      exit 1
    }
    return $p
  }
  mut d = $env.PWD
  while $d != "/" {
    if (overlay-gitdir $d | path exists) { return $d }
    $d = ($d | path dirname)
  }
  print --stderr "no overlay: pass --worktree, set ONTOREF_INTERNAL_ROOT, or cd into an overlaid project"
  exit 1
}

def main [] {
  print "internal-overlay — private dev-internal overlay (.coder/.claude), never mirrored"
  print ""
  print "  setup   <worktree> [--remote <url>] [--push]   create overlay, capture current .coder/.claude"
  print "  onboard <worktree> --remote <url>              clone the overlay into an existing checkout"
  print "  commit  <message> [--worktree <dir>]           force-add .coder/.claude and commit"
  print "  run     \"<git args>\" [--worktree <dir>]        run any git command against the overlay"
  print "  status  [--worktree <dir>]                      short status of the overlay"
  print ""
  print "  commit/run/status resolve the work-tree as: --worktree -> \$ONTOREF_INTERNAL_ROOT -> walk up from cwd."
  print "  In a jj agent workspace, set ONTOREF_INTERNAL_ROOT to the MAIN checkout (ignored .coder/.claude"
  print "  are not materialized in a fresh workspace). The overlay never gets a jj/rad/github remote."
}

def "main setup" [
  worktree: path                                   # project/member root to overlay
  --remote: string = ""                            # forgejo PRIVATE url (optional)
  --push                                           # push after commit (default: you push)
  ...paths: string                                 # dirs to track (default: .coder .claude)
] {
  let paths = (if ($paths | is-empty) { [".coder" ".claude"] } else { $paths })
  let wt = ($worktree | path expand)
  let gd = (overlay-gitdir $wt)

  if not ($wt | path exists) {
    print --stderr $"work-tree does not exist: ($wt)"
    exit 1
  }
  if ($gd | path exists) {
    print --stderr $"overlay already exists at ($gd) — use 'run' or 'status'"
    exit 1
  }

  # PRE-1 privacy: refuse if the dirs are already tracked in the PUBLIC repo —
  # they would otherwise reach the public mirror through that history.
  let pub = (^git -C $wt ls-files | complete)
  if $pub.exit_code == 0 {
    let leaked = ($pub.stdout | lines | where ($it =~ '^\.(coder|claude)/'))
    if ($leaked | length) > 0 {
      print --stderr $"PRE-1 FAILED: ($leaked | length) files under .coder/.claude are TRACKED in the public repo and would be mirrored."
      print --stderr $"  fix: git -C ($wt) rm -r --cached .coder .claude   then scrub history before creating the overlay."
      exit 1
    }
  }

  # PRE-2 privacy: the public repo must ignore the private dirs AND the overlay git-dir.
  let gi = ($wt | path join ".gitignore")
  let want = [".coder/" ".claude/" ".internal.git/"]
  let have = (if ($gi | path exists) { open --raw $gi | lines } else { [] })
  let missing = ($want | where ($it not-in $have))
  if ($missing | length) > 0 {
    $"(char nl)($missing | str join (char nl))(char nl)" | save --append --raw $gi
    print $"PRE-2: added to .gitignore -> ($missing | str join ', ')"
  }

  let pre = (git-prefix $wt)
  ^git init --bare $gd
  ^git ...($pre ++ ["config" "status.showUntrackedFiles" "no"])
  # -f is required: the work-tree's .gitignore ignores these dirs (PRE-2), and the
  # overlay's whole purpose is to track exactly those ignored paths.
  ^git ...($pre ++ ["add" "-f"] ++ $paths)
  ^git ...($pre ++ ["commit" "-m" "internal: dev-internal overlay (.coder + .claude)"])

  if ($remote | is-not-empty) {
    ^git ...($pre ++ ["remote" "add" "forgejo-priv" $remote])
    if $push {
      ^git ...($pre ++ ["push" "-u" "forgejo-priv" "HEAD"])
    } else {
      print $"remote 'forgejo-priv' set. Push yourself: nu internal-overlay.nu run ($wt) -- push -u forgejo-priv HEAD"
    }
  } else {
    print $"overlay created at ($gd). Add a private remote later: nu internal-overlay.nu run ($wt) -- remote add forgejo-priv <url>"
  }
}

def "main onboard" [
  worktree: path                # existing checkout of the PUBLIC repo
  --remote: string = ""         # private overlay url (required)
] {
  let wt = ($worktree | path expand)
  let gd = (overlay-gitdir $wt)

  if ($remote | is-empty) {
    print --stderr "--remote <private-overlay-url> is required for onboard"
    exit 1
  }
  if ($gd | path exists) {
    print --stderr $"overlay git-dir already present at ($gd)"
    exit 1
  }

  ^git clone --bare $remote $gd
  let pre = (git-prefix $wt)
  # a bare clone leaves core.bare=true and drops local config — restore both.
  ^git ...($pre ++ ["config" "core.bare" "false"])
  ^git ...($pre ++ ["config" "status.showUntrackedFiles" "no"])
  ^git ...($pre ++ ["checkout" "-f"])
  print $"onboarded: .coder/.claude materialized into ($wt)"
}

def "main commit" [
  message: string                                  # commit message
  --worktree: string = ""                          # override (else env / walk-up)
  ...paths: string                                 # tracked dirs (default: .coder .claude)
] {
  let paths = (if ($paths | is-empty) { [".coder" ".claude"] } else { $paths })
  let wt = (resolve-wt $worktree)
  let pre = (git-prefix $wt)
  # -f bypasses the work-tree .gitignore that hides these dirs from the public repo.
  ^git ...($pre ++ ["add" "-f"] ++ $paths)
  ^git ...($pre ++ ["commit" "-m" $message])
}

def "main run" [
  git_command: string           # quoted git args, e.g. "push -u forgejo-priv HEAD"
  --worktree: string = ""       # override (else env / walk-up)
] {
  let wt = (resolve-wt $worktree)
  let parts = ($git_command | split row " " | where ($it | is-not-empty))
  ^git ...((git-prefix $wt) ++ $parts)
}

def "main status" [
  --worktree: string = ""       # override (else env / walk-up)
] {
  let wt = (resolve-wt $worktree)
  ^git ...((git-prefix $wt) ++ ["status" "--short" "--branch"])
}
