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

# new-from-template — Bootstrap a new skill from a local template under docs/examples/skill-templates/.
#
# Usage:
#   bin/new-from-template --list                          List available templates
#   bin/new-from-template <template> --tokens             List replacement tokens for a template
#   bin/new-from-template <template> <skill-name> [--var KEY=VALUE]...
#                                                       Copy template into skills/<skill-name>/,
#                                                       replace [REPLACE: KEY] tokens, register
#                                                       a disabled entry in aeon.yml.

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
TEMPLATES_DIR="$ROOT/docs/examples/skill-templates"
SKILLS_DIR="$ROOT/skills"
AEON_YML="$ROOT/aeon.yml"

usage() {
  cat <<'EOF'
Usage: bin/new-from-template <template> <skill-name> [--var KEY=VALUE]...

Bootstrap a new skill from a local template.

Arguments:
  <template>         Template name (a directory under docs/examples/skill-templates/)
  <skill-name>       Name for the new skill (becomes skills/<skill-name>/)

Options:
  --list             List available templates and exit
  --tokens           Print the replacement tokens used by <template> and exit
  --var KEY=VALUE    Provide a value for [REPLACE: KEY]. Repeatable.
  --category KEY     Pack the skill belongs to (sets the SKILL.md `category:`).
                     One of: research dev crypto onchain-security social
                     productivity meta. Defaults to the template's own category.
  --help, -h         Show this help

Examples:
  bin/new-from-template --list
  bin/new-from-template crypto-tracker --tokens
  bin/new-from-template crypto-tracker my-eth-watch \
    --var TOKEN_SYMBOL=ETH \
    --var COINGECKO_ID=ethereum \
    --var ALERT_THRESHOLD_PCT=10
EOF
}

list_templates() {
  if [[ ! -d "$TEMPLATES_DIR" ]]; then
    echo "No docs/examples/skill-templates/ directory found." >&2
    return 1
  fi
  echo ""
  echo "Available templates:"
  echo ""
  local count=0
  while IFS= read -r skill_md; do
    local dir name desc
    dir="$(dirname "$skill_md")"
    name="$(basename "$dir")"
    desc=$(awk '/^description:/ { sub(/^description: */, ""); print; exit }' "$skill_md")
    if [[ ${#desc} -gt 80 ]]; then
      desc="${desc:0:77}..."
    fi
    printf "  %-22s %s\n" "$name" "$desc"
    count=$((count + 1))
  done < <(find "$TEMPLATES_DIR" -mindepth 2 -maxdepth 2 -name "SKILL.md" -type f | sort)
  echo ""
  echo "$count templates available."
  echo ""
  echo "See docs/examples/skill-templates/TEMPLATE.md for the full contract."
}

list_tokens() {
  local template="$1"
  local skill_md="$TEMPLATES_DIR/$template/SKILL.md"
  if [[ ! -f "$skill_md" ]]; then
    echo "Template '$template' not found." >&2
    return 1
  fi
  echo ""
  echo "Replacement tokens in template '$template':"
  echo ""
  local tokens
  tokens=$(grep -oE '\[REPLACE: [A-Z0-9_]+\]' "$skill_md" | sort -u | sed 's/^\[REPLACE: //;s/\]$//')
  if [[ -z "$tokens" ]]; then
    echo "  (none — template has no replacement tokens)"
  else
    while IFS= read -r tok; do
      [[ -z "$tok" ]] && continue
      if [[ "$tok" == "SKILL_NAME" ]]; then
        printf "  %-22s (auto — set to <skill-name> argument)\n" "$tok"
      else
        printf "  %s\n" "$tok"
      fi
    done <<< "$tokens"
  fi
  echo ""
}

# Parse args
if [[ $# -lt 1 ]] || [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
  usage
  exit 0
fi

if [[ "$1" == "--list" ]]; then
  list_templates
  exit 0
fi

TEMPLATE="$1"
shift

# Validate template
TEMPLATE_DIR="$TEMPLATES_DIR/$TEMPLATE"
TEMPLATE_FILE="$TEMPLATE_DIR/SKILL.md"
if [[ ! -d "$TEMPLATE_DIR" ]] || [[ ! -f "$TEMPLATE_FILE" ]]; then
  echo "Template '$TEMPLATE' not found in $TEMPLATES_DIR." >&2
  echo "Run 'bin/new-from-template --list' to see what's available." >&2
  exit 1
fi

# --tokens mode: print tokens and exit before requiring skill-name
if [[ $# -ge 1 ]] && [[ "$1" == "--tokens" ]]; then
  list_tokens "$TEMPLATE"
  exit 0
fi

# Need skill name now
if [[ $# -lt 1 ]]; then
  echo "Missing <skill-name>. See 'bin/new-from-template --help'." >&2
  exit 1
fi

SKILL_NAME="$1"
shift

# Validate skill name (alphanumeric, dashes, underscores)
if [[ ! "$SKILL_NAME" =~ ^[a-z0-9][a-z0-9_-]*$ ]]; then
  echo "Skill name '$SKILL_NAME' is invalid. Use lowercase letters, digits, dashes, underscores; must start with a letter or digit." >&2
  exit 1
fi

DEST_DIR="$SKILLS_DIR/$SKILL_NAME"
DEST_FILE="$DEST_DIR/SKILL.md"

if [[ -e "$DEST_DIR" ]]; then
  echo "skills/$SKILL_NAME already exists — refusing to overwrite. Choose a different name or rm -rf the existing directory first." >&2
  exit 1
fi

# Collect --var assignments using parallel arrays (bash 3.2 compatible — stock
# macOS /bin/bash does not support `declare -A`). Always include SKILL_NAME.
VAR_KEYS=()
VAR_VALS=()
set_var() {
  local k="$1" v="$2" i
  for i in "${!VAR_KEYS[@]}"; do
    if [[ "${VAR_KEYS[$i]}" == "$k" ]]; then
      VAR_VALS[$i]="$v"
      return
    fi
  done
  VAR_KEYS+=("$k")
  VAR_VALS+=("$v")
}
set_var "SKILL_NAME" "$SKILL_NAME"

CATEGORY=""
while [[ $# -gt 0 ]]; do
  case "$1" in
    --category)
      if [[ $# -lt 2 ]]; then
        echo "--category requires a value." >&2
        exit 1
      fi
      CATEGORY="$2"
      case "$CATEGORY" in
        research|dev|crypto|onchain-security|social|productivity|meta) ;;
        *)
          echo "Invalid --category '$CATEGORY'. One of: research dev crypto onchain-security social productivity meta." >&2
          echo "(core and fleet are curated in packs.config.json, not set here.)" >&2
          exit 1
          ;;
      esac
      shift 2
      ;;
    --var)
      if [[ $# -lt 2 ]]; then
        echo "--var requires a KEY=VALUE argument." >&2
        exit 1
      fi
      pair="$2"
      key="${pair%%=*}"
      val="${pair#*=}"
      if [[ -z "$key" ]] || [[ "$key" == "$pair" ]]; then
        echo "Invalid --var '$pair' — expected KEY=VALUE." >&2
        exit 1
      fi
      # KEY must be a [REPLACE: ...] token name — uppercase, digits, underscore,
      # leading letter/underscore. Rejecting anything else closes a sed-injection
      # path through the s|\[REPLACE:…KEY…\]|val|g pipeline below.
      if [[ ! "$key" =~ ^[A-Z_][A-Z0-9_]*$ ]]; then
        echo "Invalid --var KEY '$key' — must match ^[A-Z_][A-Z0-9_]*$." >&2
        exit 1
      fi
      set_var "$key" "$val"
      shift 2
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      exit 1
      ;;
  esac
done

# Copy + substitute
mkdir -p "$DEST_DIR"

# Build a sed pipeline of `s|...|...|g` replacements, one per token. The `|`
# delimiter avoids URL-path conflicts in replacement values; `\`, `&`, and `|`
# are escaped in values so they're treated as literals by sed.
sed_args=()
for i in "${!VAR_KEYS[@]}"; do
  key="${VAR_KEYS[$i]}"
  val="${VAR_VALS[$i]}"
  esc_val=$(printf '%s' "$val" | sed -e 's/[\\&|]/\\&/g')
  sed_args+=(-e "s|\\[REPLACE:[[:space:]]*${key}\\]|${esc_val}|g")
done

sed "${sed_args[@]}" "$TEMPLATE_FILE" > "$DEST_FILE"

# Apply --category to the new skill's frontmatter (templates ship a default;
# this overrides it). Replaces the `category:` line if present, else inserts it
# right after `name:`. The category routes the skill into its pack (packs.json).
if [[ -n "$CATEGORY" ]]; then
  CATEGORY="$CATEGORY" python3 - "$DEST_FILE" <<'PY'
import os, re, sys
cat = os.environ["CATEGORY"]
path = sys.argv[1]
lines = open(path).read().split("\n")
if lines and lines[0].strip() == "---":
    end = next((i for i in range(1, len(lines)) if lines[i].strip() == "---"), None)
    if end is not None:
        block = lines[1:end]
        # category may be top-level (legacy) or nested under `metadata:` (spec
        # form). Replace in place preserving indentation; else insert into the
        # metadata block if present, else top-level after name.
        ci = next((j for j, l in enumerate(block) if re.match(r"^\s*category:", l)), None)
        if ci is not None:
            indent = re.match(r"^\s*", block[ci]).group(0)
            block[ci] = f"{indent}category: {cat}"
        else:
            mi = next((j for j, l in enumerate(block) if re.match(r"^metadata:", l)), None)
            if mi is not None:
                block.insert(mi + 1, f"  category: {cat}")
            else:
                ni = next((j for j, l in enumerate(block) if re.match(r"^name:", l)), None)
                block.insert((ni + 1) if ni is not None else 0, f"category: {cat}")
        open(path, "w").write("\n".join(["---"] + block + ["---"] + lines[end + 1:]))
PY
fi

# Detect any tokens that remain unreplaced
remaining=$(grep -oE '\[REPLACE: [A-Z0-9_]+\]' "$DEST_FILE" | sort -u || true)

# Register in aeon.yml if not already present and the fallback marker exists.
registered=false
if ! grep -qE "^[[:space:]]+${SKILL_NAME}:" "$AEON_YML" 2>/dev/null; then
  if grep -q "# --- Fallback" "$AEON_YML"; then
    awk -v entry="  ${SKILL_NAME}: { enabled: false, schedule: \"0 12 * * *\", var: \"\" } # bootstrapped from template '${TEMPLATE}'" \
      '/^  # --- Fallback/ { print entry } { print }' \
      "$AEON_YML" > "${AEON_YML}.tmp" && mv "${AEON_YML}.tmp" "$AEON_YML"
    registered=true
  fi
fi

# Report
echo ""
echo "✓ Created skills/$SKILL_NAME/SKILL.md from template '$TEMPLATE'."
if [[ -n "$CATEGORY" ]]; then
  echo "✓ Category set to '$CATEGORY' (regenerate the catalog with bin/generate-skills-json && bin/generate-packs-json to slot it into its pack)."
fi
if [[ "$registered" == "true" ]]; then
  echo "✓ Registered in aeon.yml (disabled, schedule: 0 12 * * *)."
else
  echo "  (Skipped aeon.yml registration — entry already exists or no fallback marker found.)"
fi

if [[ -n "$remaining" ]]; then
  echo ""
  echo "⚠ Unreplaced tokens — edit skills/$SKILL_NAME/SKILL.md before enabling:"
  while IFS= read -r tok; do
    [[ -z "$tok" ]] && continue
    echo "    $tok"
  done <<< "$remaining"
fi

echo ""
echo "Next:"
echo "  1. Open skills/$SKILL_NAME/SKILL.md and review the customised content."
echo "  2. Toggle enabled: true in aeon.yml when ready, or run from the dashboard."
echo "  3. (Optional) Set var: \"...\" on the aeon.yml entry to focus the skill."
