#!/bin/bash
# verify-repl — compliance checker for the OpenCode Engineering Discipline
#
# Usage: verify-repl <org-directory>
#   Scans all .org files in the given directory for violations of:
#   1. REPL-First: every (defun|defmacro|defvar|defparameter|defstruct|defmethod|defclass)
#      block must have ";; REPL-VERIFIED:" on the line above #+begin_src lisp
#   2. One-per-block: each #+begin_src lisp block must contain exactly one top-level form
#   3. Prose-before-code: each code block must be preceded by an Org headline
#
# Returns 0 if all checks pass, 1 if violations found.

set -euo pipefail

ORG_DIR="${1:-}"
if [ -z "$ORG_DIR" ] || [ ! -d "$ORG_DIR" ]; then
    echo "Usage: verify-repl <org-directory>"
    exit 1
fi

VIOLATIONS=0
FILES_CHECKED=0

# Blacklist: files exempt from REPL verification (core infrastructure, tests)
# Override with $VERIFY_REPL_EXCLUDE (space-separated filenames).
# Example: VERIFY_REPL_EXCLUDE="setup.org package.lisp" verify-repl org/
DEFAULT_BLACKLIST=(
    "core-defpackage.org"
    "core-manifest.org"
    "core-skills.org"
    "core-communication.org"
    "package.lisp"
    "setup.org"
)

if [ -n "${VERIFY_REPL_EXCLUDE:-}" ]; then
    IFS=' ' read -ra BLACKLIST <<< "$VERIFY_REPL_EXCLUDE"
else
    BLACKLIST=("${DEFAULT_BLACKLIST[@]}")
fi

is_blacklisted() {
    local fname
    fname=$(basename "$1")
    for bl in "${BLACKLIST[@]}"; do
        [ "$fname" = "$bl" ] && return 0
    done
    return 1
}

check_file() {
    local file="$1"
    local fname
    fname=$(basename "$file")
    local in_block=0
    local block_start=0
    local prev_line=""
    local prev_was_headline=0
    local block_content=""
    local line_no=0
    local has_repl_verify=0
    local def_count=0
    local violations_in_file=0

    is_blacklisted "$file" && return 0

    FILES_CHECKED=$((FILES_CHECKED + 1))

    while IFS= read -r line || [ -n "$line" ]; do
        line_no=$((line_no + 1))
        local trimmed="${line#"${line%%[![:space:]]*}"}"

        # Track headlines
        if echo "$trimmed" | grep -qE '^\*+[[:space:]]'; then
            prev_was_headline=1
        fi

        # Enter code block
        if echo "$trimmed" | grep -qE '^#\+begin_src[[:space:]]+lisp'; then
            in_block=1
            block_start=$line_no
            block_content=""
            def_count=0
            has_repl_verify=0
            # Check for REPL-VERIFIED comment on previous line(s)
            # Matches ";; REPL-VERIFIED:" or ";;  REPL-VERIFIED:" etc.
            if echo "$prev_line" | grep -qE ';; +REPL[-_]VERIFIED:'; then
                has_repl_verify=1
            fi
            # Check for prose requirement: was there a headline before this block?
            if [ "$prev_was_headline" -eq 0 ]; then
                echo "  $fname:$block_start: PROSE-BEFORE-CODE: no Org headline before code block"
                violations_in_file=$((violations_in_file + 1))
            fi
        fi

        # Inside code block: collect content
        if [ "$in_block" -eq 1 ]; then
            if echo "$trimmed" | grep -qE '^#\+end_src'; then
                in_block=0
                # Check: REPL verification for definition blocks
                if [ "$def_count" -gt 0 ] && [ "$has_repl_verify" -eq 0 ]; then
                    echo "  $fname:$block_start: REPL-FIRST: $(if [ "$def_count" -gt 1 ]; then echo "$def_count definitions"; else echo "defun/defmacro"; fi) without REPL-VERIFIED comment"
                    violations_in_file=$((violations_in_file + 1))
                fi
                # Check: one-per-block
                if [ "$def_count" -gt 1 ]; then
                    echo "  $fname:$block_start: ONE-PER-BLOCK: $def_count definitions in a single block (must be exactly 1)"
                    violations_in_file=$((violations_in_file + 1))
                fi
                prev_was_headline=0
                block_content=""
            else
                # Count definitions in block
                if echo "$trimmed" | grep -qE '^\((defun|defmacro|defvar|defparameter|defstruct|defmethod|defclass)[[:space:](]'; then
                    def_count=$((def_count + 1))
                fi
            fi
        fi

        prev_line="$line"
    done < "$file"

    if [ "$violations_in_file" -gt 0 ]; then
        echo "  ✗ $fname: $violations_in_file violation(s)"
        VIOLATIONS=$((VIOLATIONS + violations_in_file))
    fi
}

echo "=== REPL Compliance Check ==="
echo "Directory: $ORG_DIR"
echo ""

for file in "$ORG_DIR"/*.org; do
    [ -f "$file" ] || continue
    check_file "$file"
done

echo ""
echo "Files checked: $FILES_CHECKED"
echo "Violations:    $VIOLATIONS"

if [ "$VIOLATIONS" -eq 0 ]; then
    echo "Status:        ✓ PASS — all checks satisfied"
    exit 0
else
    echo "Status:        ✗ FAIL — fix violations before committing"
    exit 1
fi
