#!/usr/bin/env bash
# beagle-init — scaffold a new beagle project or add Claude Code hooks.
#
# Usage:
#   beagle-init [--hooks] [--target TARGET] [DIRECTORY]
#
# Options:
#   --hooks        Also scaffold .claude/ hooks for the repair/check loop
#   --target T     Default target: clj (default), js, nix, sql
#   DIRECTORY      Project directory (default: current directory)

set -euo pipefail

# --- Parse args ---
TARGET="clj"
HOOKS=false
DIR="."

while [[ $# -gt 0 ]]; do
    case "$1" in
        --hooks)  HOOKS=true; shift ;;
        --target) TARGET="$2"; shift 2 ;;
        -*)       echo "unknown option: $1" >&2; exit 1 ;;
        *)        DIR="$1"; shift ;;
    esac
done

# --- Resolve beagle install (before cd) ---
BEAGLE_PATH="${BEAGLE_PATH:-}"
if [[ -z "$BEAGLE_PATH" ]]; then
    SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
    if [[ -f "$SCRIPT_DIR/bin/beagle-syntax" ]]; then
        BEAGLE_PATH="$SCRIPT_DIR"
    fi
fi

# Tracked hook-worker templates (copied into scaffolded projects, not inlined).
BEAGLE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
HOOK_TEMPLATES="$BEAGLE_ROOT/share/claude-hooks"

mkdir -p "$DIR"
cd "$DIR"

# --- Target → lang/extension ---
# Nix is the live target; non-Nix targets are dormant and need
# BEAGLE_ALL_TARGETS=1 at runtime, but the scaffolding can still
# be generated against them.
case "$TARGET" in
    nix)  LANG="beagle/nix";  EXT="bnix" ;;
    clj)  LANG="beagle";      EXT="bclj"  ;; # dormant
    js)   LANG="beagle/js";   EXT="bjs"   ;; # dormant
    sql)  LANG="beagle/sql";  EXT="bsql"  ;; # dormant
    *)    echo "unknown target: $TARGET (nix is live; clj/js/sql are dormant)" >&2; exit 1 ;;
esac

# --- Detect an already-initialized project ---
# `--hooks` on an EXISTING project should ONLY wire the repair hook — never drop
# starter files (src/main, CLAUDE.md, flake.nix, .envrc) into a populated repo.
# A genuinely empty/new dir still gets the full scaffold (+ hooks).
SCAFFOLD_PROJECT=true
if [[ -f "CLAUDE.md" || -f ".claude/settings.json" || -d ".git" \
      || -f "package.json" || -f "flake.nix" || -f "deno.json" ]] \
   || compgen -G "src/*.b*" >/dev/null 2>&1 \
   || compgen -G "*.b*"     >/dev/null 2>&1; then
    SCAFFOLD_PROJECT=false
fi

# --- Write example source (new projects only) ---
if [[ "$SCAFFOLD_PROJECT" == true && ! -f "src/main.$EXT" ]]; then
    mkdir -p src
    cat > "src/main.$EXT" << SRCEOF
#lang $LANG
(ns main)

(def greeting "hello from beagle")
SRCEOF
    echo "  created src/main.$EXT"
fi

# --- Write CLAUDE.md (new projects only) ---
if [[ "$SCAFFOLD_PROJECT" == true && ! -f "CLAUDE.md" ]]; then
    cat > CLAUDE.md << 'CLEOF'
# Project — beagle

This project uses **beagle**, a typed language that compiles to multiple targets.

## Session start

1. Confirm daemon: `beagle-daemon status` — start with `beagle-daemon start` if not running
2. The PostToolUse hook auto-starts the daemon on first edit

## After every edit (automatic via hook)

The PostToolUse hook fires on Edit/Write to beagle files. It runs:
- `beagle-syntax FILE` — structural delimiter check
- `beagle-daemon query check-enriched FILE` — type errors with fix hints

If it reports a syntax error, fix delimiters first — do not type-check
or inspect deeper errors until delimiters pass.

## Tools

- `beagle-check SOURCE` — type check a file
- `beagle-build SOURCE` — compile to target
- `beagle-expand SOURCE` — show macro expansion
- `beagle-sig NAME FILE...` — typed signature lookup
- `beagle-fields RECORD FILE...` — record field types
- `beagle-syntax --repair --write FILE` — auto-fix delimiter errors

For the form set, types, and stdlib: read `parse.rkt` and
`stdlib-nix.rkt` in the beagle source. There is no static reference
document — it would go stale within a day.
CLEOF
    echo "  created CLAUDE.md"
fi

# --- Hooks ---
if [[ "$HOOKS" == true ]]; then
    mkdir -p .claude/hooks

    # settings.json — idempotently MERGE the PostToolUse repair hook into any
    # existing config instead of only writing when absent. Never clobbers other
    # settings/hooks; re-running is a safe no-op. This is what makes
    # `beagle init --hooks` a one-shot "sync" for already-initialized repos.
    python3 - << 'PYEOF'
import json, os
PATH = ".claude/settings.json"
CMD = ".claude/hooks/post-edit-check.sh"
MATCHER = "Edit|Write|MultiEdit"
data = {}
if os.path.exists(PATH):
    try:
        with open(PATH) as f:
            data = json.load(f) or {}
    except Exception as e:
        raise SystemExit(f"  ERROR: {PATH} is not valid JSON ({e}); left untouched")
if not isinstance(data, dict):
    raise SystemExit(f"  ERROR: {PATH} is not a JSON object; left untouched")
hooks = data.setdefault("hooks", {})
ptu = hooks.setdefault("PostToolUse", [])
if not isinstance(ptu, list):
    raise SystemExit(f"  ERROR: hooks.PostToolUse in {PATH} is not a list; left untouched")
def wired(entry):
    return isinstance(entry, dict) and any(
        isinstance(h, dict) and h.get("command") == CMD
        for h in entry.get("hooks", []))
if any(wired(e) for e in ptu):
    print("  .claude/settings.json — repair hook already wired (no change)")
else:
    ptu.append({
        "matcher": MATCHER,
        "hooks": [{"type": "command", "command": CMD, "timeout": 10}],
    })
    with open(PATH, "w") as f:
        json.dump(data, f, indent=2)
        f.write("\n")
    print(f"  wired PostToolUse repair hook into {PATH}")
PYEOF

    # Shell wrapper — inject BEAGLE_PATH discovered at init time
    cat > .claude/hooks/post-edit-check.sh << HEOF
#!/usr/bin/env bash
set -euo pipefail
export BEAGLE_PATH="\${BEAGLE_PATH:-${BEAGLE_PATH}}"
HOOK_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
MODE="simple"
PROJECT_DIR="\$(cd "\$HOOK_DIR/../.." && pwd)"
POOL_CFG="\$PROJECT_DIR/.beagle/pool.json"
if [[ -f "\$POOL_CFG" ]]; then
    _mode=\$(python3 -c "import json,sys; print(json.load(open('\$POOL_CFG')).get('mode','simple'))" 2>/dev/null || true)
    [[ -n "\$_mode" ]] && MODE="\$_mode"
fi
INPUT=\$(cat)
if [[ "\$MODE" == "pool" && -f "\$HOOK_DIR/post_edit_check_pool.py" ]]; then
    exec python3 "\$HOOK_DIR/post_edit_check_pool.py" "\$INPUT"
else
    exec python3 "\$HOOK_DIR/post_edit_check_simple.py" "\$INPUT"
fi
HEOF
    chmod +x .claude/hooks/post-edit-check.sh

    # Simple mode worker
    # Hook workers — copied from the tracked templates (canonical, portable
    # find_tool resolution), not inlined. Install BOTH so `mode: pool` works.
    if [[ -d "$HOOK_TEMPLATES" ]]; then
        cp "$HOOK_TEMPLATES/post_edit_check_simple.py" .claude/hooks/
        cp "$HOOK_TEMPLATES/post_edit_check_pool.py"   .claude/hooks/
        chmod +x .claude/hooks/post_edit_check_simple.py .claude/hooks/post_edit_check_pool.py
        echo "  installed hook workers (simple + pool)"
    else
        echo "  WARNING: hook templates missing at $HOOK_TEMPLATES" >&2
    fi

    echo "  created .claude/hooks/ (simple mode)"
fi

# --- Write flake.nix (new projects only; follows beagle's nixpkgs) ---
if [[ "$SCAFFOLD_PROJECT" == true && ! -f "flake.nix" && -n "$BEAGLE_PATH" ]]; then
    cat > flake.nix << FEOF
{
  inputs = {
    beagle.url = "path:${BEAGLE_PATH}";
    nixpkgs.follows = "beagle/nixpkgs";
  };

  outputs = { nixpkgs, beagle, ... }:
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs { inherit system; };
    in {
      devShells.\${system}.default = pkgs.mkShell {
        packages = with pkgs; [ racket ];
      };
    };
}
FEOF
    echo "  created flake.nix (follows beagle/nixpkgs)"
fi

# --- Write .envrc (new projects only) ---
if [[ "$SCAFFOLD_PROJECT" == true && ! -f ".envrc" && -f "flake.nix" ]]; then
    echo "use flake" > .envrc
    echo "  created .envrc"
fi

echo ""
if [[ "$SCAFFOLD_PROJECT" == true ]]; then
    echo "beagle project initialized (target: $TARGET)"
else
    echo "existing project detected — left source/config untouched"
fi
if [[ "$HOOKS" == true ]]; then
    echo "Claude Code repair hook wired — syntax + type errors (and deterministic"
    echo "paren auto-balancing) run on every edit. Restart the session (or rely on"
    echo "settings hot-reload) to activate it."
    echo "To switch to pool mode: echo '{\"mode\":\"pool\"}' > .beagle/pool.json"
fi
