#!/usr/bin/env bash
# Idempotent ADMIN-SKILLS.md bootstrap (Task 698). Sibling of agents-md-bootstrap.sh.
#
# Usage: admin-skills-bootstrap.sh <account_dir> <plugins_dir> [<owned_set_ts>]
#
# Scans <plugins_dir>/*/skills/*/SKILL.md and writes
# <account_dir>/agents/admin/ADMIN-SKILLS.md — one `- name: description` line per
# admin-usable skill, sorted by slug.
#
# Admin-usable = the SKILL.md "Invoked by/from" declaration does NOT name a
# specialist (`specialists:<name>`) AND the slug is not in the content-producer
# authoring owned-set. A skill with no parseable declaration is excluded
# (fail-safe — never silently offer a possibly-specialist-owned skill) and
# reported, so the offender is visible rather than dropped.
#
# owned_set_ts defaults to the canonical module in the admin MCP source tree; the
# quoted slugs between its array brackets are the shared owned-set (one source of
# truth with the Task 516 runtime gate in skill-resolution.ts).
#
# Observability (stdout, two-space indented to match setup-account.sh):
#   [admin-skills] scanned=<N> admin-usable=<M> no-declaration=<K>
#   [admin-skills] skill=<name> missing-declaration   (one per offender, when K>0)
# Failure signature: admin-usable=0 while scanned>0, or any missing-declaration line.

set -euo pipefail

ACCOUNT_DIR="${1:?Usage: admin-skills-bootstrap.sh <account_dir> <plugins_dir> [owned_set_ts]}"
PLUGINS_DIR="${2:?Usage: admin-skills-bootstrap.sh <account_dir> <plugins_dir> [owned_set_ts]}"
OWNED_TS="${3:-$PLUGINS_DIR/admin/mcp/src/content-producer-authoring-skills.ts}"
OUT="$ACCOUNT_DIR/agents/admin/ADMIN-SKILLS.md"

mkdir -p "$(dirname "$OUT")"

# Owned-set: quoted slugs inside the canonical array. Missing file -> empty set
# (the declaration scan still excludes specialist-named skills; the owned-set is
# only the belt-and-suspenders guard against a declaration regression).
OWNED=""
if [ -f "$OWNED_TS" ]; then
  OWNED=$(grep -oE '"[a-z0-9-]+"' "$OWNED_TS" | tr -d '"' || true)
fi
is_owned() { printf '%s\n' "$OWNED" | grep -qx "$1"; }

# Robust frontmatter description extraction (single-line, folded `>`, literal `|`),
# mirroring parseSkillFrontmatter in skill-resolution.ts. Block scalars join their
# indented continuation lines with single spaces.
extract_desc() {
  python3 - "$1" <<'PY'
import sys, re
text = open(sys.argv[1], encoding="utf-8", errors="replace").read()
m = re.match(r"^---\r?\n(.*?)\r?\n---(?:\r?\n|$)", text, re.S)
if not m:
    print(""); sys.exit(0)
lines = m.group(1).split("\n")
out = ""
for i, line in enumerate(lines):
    hm = re.match(r"^description:[ \t]*(.*)$", line)
    if not hm:
        continue
    inline = hm.group(1).strip()
    if inline and not re.match(r"^[|>][+-]?[1-9]?[ \t]*(?:#.*)?$", inline):
        if (inline[:1], inline[-1:]) in (('"', '"'), ("'", "'")):
            inline = inline[1:-1]
        out = inline
    else:
        parts = []
        for cont in lines[i + 1:]:
            if re.match(r"^[A-Za-z][\w-]*:", cont):
                break
            t = cont.strip()
            if t:
                parts.append(t)
        out = " ".join(parts)
    break
print(out)
PY
}

_scanned=0; _usable=0; _nodecl=0
TMP=$(mktemp)
for skill in "$PLUGINS_DIR"/*/skills/*/SKILL.md; do
  [ -f "$skill" ] || continue
  _scanned=$((_scanned + 1))
  slug=$(basename "$(dirname "$skill")")
  decl=$(grep -iE "invoked (by|from)" "$skill" | head -1 || true)
  if [ -z "$decl" ]; then
    _nodecl=$((_nodecl + 1))
    echo "  [admin-skills] skill=$slug missing-declaration"
    continue
  fi
  # Specialist-owned iff the invoked clause names a specialist BEFORE its first
  # period: "Invoked from `specialists:<name>`". A later `specialists:` mention
  # after a period is downstream-routing prose, not ownership (e.g. the admin's
  # unzip-attachment names content-producer/librarian as where it forwards to).
  printf '%s' "$decl" | grep -qiE "invoked (by|from)[^.]*specialists:" && continue
  is_owned "$slug" && continue                                # owned-set guard
  desc=$(extract_desc "$skill")
  printf -- '- %s: %s\n' "$slug" "$desc" >> "$TMP"
  _usable=$((_usable + 1))
done

{
  printf '# Admin-usable skills\n\n'
  printf 'Skills the admin agent may load directly with `skill-load skillName=<name>`.\n'
  printf 'Specialist-owned skills are not listed; dispatch their specialist instead.\n\n'
  sort "$TMP"
} > "$OUT"
rm -f "$TMP"

echo "  [admin-skills] scanned=$_scanned admin-usable=$_usable no-declaration=$_nodecl"
