#!/usr/bin/env bash
set -eo pipefail

# generate-skills-json — Build skills.json manifest from all skills/*/SKILL.md files
#
# Usage:
#   bin/generate-skills-json              Generate the catalog at catalog/skills.json
#   bin/generate-skills-json --pretty     Pretty-print the output
#
# The manifest enables one-command skill installation and marketplace discovery.
# Each entry includes: name, slug, description, category, default var,
# required secrets, and install command.
#
# The catalog describes the *skill* (from skills/<slug>/SKILL.md + git), never
# per-deployment operator config. Schedules live in aeon.yml — the source of
# truth the dashboard reads live — and are deliberately NOT mirrored here, so
# editing a schedule (or an upstream sync) can't make this manifest go stale.

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SKILLS_DIR="$ROOT/skills"
OUTPUT="$ROOT/catalog/skills.json"

PRETTY=false
if [[ "${1:-}" == "--pretty" ]]; then
  PRETTY=true
fi

# Count files in skill directory (excluding SKILL.md)
count_files() {
  local skill_dir="$1"
  find "$skill_dir" -type f ! -name "SKILL.md" 2>/dev/null | wc -l | tr -d ' '
}

# Get 7-char git SHA of last commit touching a SKILL.md
get_skill_sha() {
  local slug="$1"
  git -C "$ROOT" log --follow --format="%H" -1 -- "skills/$slug/SKILL.md" 2>/dev/null | cut -c1-7 || echo ""
}

# Get YYYY-MM-DD date of last commit touching a SKILL.md
get_skill_updated() {
  local slug="$1"
  git -C "$ROOT" log --follow --format="%as" -1 -- "skills/$slug/SKILL.md" 2>/dev/null || echo ""
}

# Read one frontmatter scalar (first '---' block) from a SKILL.md.
#   fm <file> <field>        value after 'field:' (verbatim; no quote strip)
#   fm <file> <field> strip  additionally strip all double-quotes (gsub /"/)
fm() {
  awk -v f="$2" -v q="${3:-}" '
    /^---$/{n++; next}
    n==1 && $0 ~ "^"f":" {
      line=$0
      sub("^"f": *", "", line)
      # YAML block scalar (">", ">-", "|", "|-", ...): the value is the indented
      # block that follows, not the marker. Community SKILL.md files lean on this
      # for long descriptions; reading only this line records the literal ">-" as
      # the description and the catalog/dashboard shows that. Fold the block into
      # one space-joined line.
      if (q=="fold" && line ~ /^[|>][-+0-9]*$/) {
        val=""
        while ((getline nxt) > 0) {
          if (nxt ~ /^---$/ || nxt !~ /^[ \t]/) break
          gsub(/^[ \t]+/, "", nxt); gsub(/[ \t]+$/, "", nxt)
          if (nxt == "") continue
          val = (val == "" ? nxt : val " " nxt)
        }
        line=val
      }
      if (q=="strip") gsub(/"/, "", line)
      print line
      exit
    }
  ' "$1"
}

# Read one key nested under the `metadata:` block (Agent Skills spec extension
# point). Returns empty if there is no metadata block or no such key, so callers
# fall back to the legacy top-level scalar — migrated and unmigrated skills
# coexist.
fmeta() {
  awk -v k="$2" '
    /^---$/{n++; next}
    n!=1{next}
    /^metadata:/{inmeta=1; next}
    inmeta && /^[^ \t]/{inmeta=0}
    inmeta && $0 ~ "^[ \t]+"k":" {
      line=$0
      sub("^[ \t]+"k": *", "", line)
      gsub(/"/, "", line)
      print line
      exit
    }
  ' "$1"
}

# Start JSON output
echo -n '{"version":"1.0","generated":"' > "$OUTPUT"
echo -n "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$OUTPUT"
echo -n '","repo":"aeonfun/aeon","total":0,"categories":{"core":"Core","evolution":"Evolution","basics":"Basics","dev":"Dev & Code","crypto":"Crypto & Markets","productivity":"Productivity"},"skills":[' >> "$OUTPUT"

TOTAL=0
FIRST=true

for skill_dir in "$SKILLS_DIR"/*/; do
  skill_file="$skill_dir/SKILL.md"
  [[ -f "$skill_file" ]] || continue

  slug=$(basename "$skill_dir")

  # Parse frontmatter. Display fields prefer the `metadata:` block (Agent Skills
  # spec form) and fall back to the legacy top-level scalar. For a migrated skill
  # the top-level `name:` is the slug (spec identifier) and the human title lives
  # in metadata.title.
  name=$(fmeta "$skill_file" title)
  [[ -z "$name" ]] && name=$(fm "$skill_file" name)
  description=$(fm "$skill_file" description fold)
  var=$(fmeta "$skill_file" var)
  [[ -z "$var" ]] && var=$(fm "$skill_file" var strip)

  # Category is declared in each SKILL.md frontmatter — the single source of
  # truth. A skill with no category falls back to "other"; the packs generator
  # parks those in the Lab catch-all rather than failing.
  category=$(fmeta "$skill_file" category)
  [[ -z "$category" ]] && category=$(fm "$skill_file" category strip)
  [[ -z "$category" ]] && category="other"

  # requires: [KEY, KEY2?]  →  [{"key":"KEY","optional":false},{"key":"KEY2","optional":true}]
  # `?` suffix marks a "works better" (optional) credential; bare names are required.
  requires_raw=$(awk '
    /^---$/{n++; next} n!=1{next}
    collecting {
      if ($0 ~ /^[ \t]*-[ \t]*/) { it=$0; sub(/^[ \t]*-[ \t]*/,"",it); sub(/[ \t]*#.*/,"",it); gsub(/[ \t]/,"",it); if(it!="") acc=(acc==""?it:acc","it); next }
      collecting=0; print acc; exit
    }
    /^[^ \t]/{im=0} /^metadata:/{im=1}
    /^requires:/ || (im && /^[ \t]+requires:/){
      if ($0 ~ /\[/) { line=$0; sub(/^[ \t]*requires:[ \t]*\[/,"",line); sub(/\].*/,"",line); print line; exit }
      collecting=1; next
    }
    END { if (collecting) print acc }
  ' "$skill_file")
  requires_json="["
  if [[ -n "$requires_raw" ]]; then
    rfirst=true
    IFS=',' read -ra rparts <<< "$requires_raw"
    for raw in "${rparts[@]}"; do
      key=$(echo "$raw" | tr -d ' ')
      [[ -z "$key" ]] && continue
      if [[ "$key" == *"?" ]]; then optional="true"; key="${key%\?}"; else optional="false"; fi
      [[ "$rfirst" == "true" ]] && rfirst=false || requires_json+=","
      requires_json+="{\"key\":\"$key\",\"optional\":$optional}"
    done
  fi
  requires_json+="]"

  # mcp: [base, glim?]  →  [{"slug":"base","optional":false},{"slug":"glim","optional":true}]
  mcp_raw=$(awk '
    /^---$/{n++; next} n!=1{next}
    collecting {
      if ($0 ~ /^[ \t]*-[ \t]*/) { it=$0; sub(/^[ \t]*-[ \t]*/,"",it); sub(/[ \t]*#.*/,"",it); gsub(/[ \t]/,"",it); if(it!="") acc=(acc==""?it:acc","it); next }
      collecting=0; print acc; exit
    }
    /^[^ \t]/{im=0} /^metadata:/{im=1}
    /^mcp:/ || (im && /^[ \t]+mcp:/){
      if ($0 ~ /\[/) { line=$0; sub(/^[ \t]*mcp:[ \t]*\[/,"",line); sub(/\].*/,"",line); print line; exit }
      collecting=1; next
    }
    END { if (collecting) print acc }
  ' "$skill_file")
  mcp_json="["
  if [[ -n "$mcp_raw" ]]; then
    mfirst=true
    IFS=',' read -ra mparts <<< "$mcp_raw"
    for raw in "${mparts[@]}"; do
      mslug=$(echo "$raw" | tr -d ' ')
      [[ -z "$mslug" ]] && continue
      if [[ "$mslug" == *"?" ]]; then optional="true"; mslug="${mslug%\?}"; else optional="false"; fi
      [[ "$mfirst" == "true" ]] && mfirst=false || mcp_json+=","
      mcp_json+="{\"slug\":\"$mslug\",\"optional\":$optional}"
    done
  fi
  mcp_json+="]"

  # Get metadata
  extra_files=$(count_files "$skill_dir")
  sha=$(get_skill_sha "$slug")
  updated=$(get_skill_updated "$slug")

  # Escape JSON strings
  name="${name//\\/\\\\}"
  name="${name//\"/\\\"}"
  description="${description//\\/\\\\}"
  description="${description//\"/\\\"}"

  if [[ "$FIRST" == "true" ]]; then
    FIRST=false
  else
    echo -n ',' >> "$OUTPUT"
  fi

  echo -n "{\"slug\":\"$slug\",\"name\":\"$name\",\"description\":\"$description\",\"category\":\"$category\",\"var\":\"$var\",\"requires\":$requires_json,\"mcp\":$mcp_json,\"files\":$extra_files,\"sha\":\"$sha\",\"updated\":\"$updated\",\"install\":\"bin/add-skill aeonfun/aeon $slug\"}" >> "$OUTPUT"

  TOTAL=$((TOTAL + 1))
done

echo -n '],"install_all":"bin/add-skill aeonfun/aeon --all","install_one":"bin/add-skill aeonfun/aeon <skill-name>"}' >> "$OUTPUT"

# Patch total count (macOS-compatible sed)
if [[ "$(uname)" == "Darwin" ]]; then
  sed -i '' "s/\"total\":0/\"total\":$TOTAL/" "$OUTPUT"
else
  sed -i "s/\"total\":0/\"total\":$TOTAL/" "$OUTPUT"
fi

# Pretty-print if requested and python3 is available
if [[ "$PRETTY" == "true" ]] && command -v python3 &>/dev/null; then
  python3 -m json.tool "$OUTPUT" > "${OUTPUT}.tmp" && mv "${OUTPUT}.tmp" "$OUTPUT"
fi

echo "Generated $OUTPUT with $TOTAL skills"
