#!/usr/bin/env bash
# commit-msg - CLEO task ID enforcement hook
#
# Validates commit messages contain T#### task references.
# Checks task existence directly against .cleo/tasks.db (SQLite, canonical per ADR-006).
#
# Supports conventional commit scopes feat(T####): and suffix (T####) patterns.
#
# Installation: Automatically installed via `cleo init`
# Manual: cp templates/git-hooks/commit-msg .git/hooks/commit-msg && chmod +x .git/hooks/commit-msg

set -euo pipefail

MSG_FILE="$1"
COMMIT_MSG=$(cat "$MSG_FILE")

# ============================================================================
# BYPASS DETECTION
# ============================================================================

# Auto-bypass for automated commits (merges, reverts, CI/CD)
if echo "$COMMIT_MSG" | grep -qE '^Merge (branch|pull request)'; then
    exit 0
fi

if echo "$COMMIT_MSG" | grep -qE '^Revert '; then
    exit 0
fi

if [[ -n "${CI:-}" || -n "${GITHUB_ACTIONS:-}" || -n "${GITLAB_CI:-}" ]]; then
    exit 0
fi

# Auto-bypass for chore(cleo) checkpoints
if echo "$COMMIT_MSG" | grep -qE '^chore\(cleo\)'; then
    exit 0
fi

# Auto-bypass for release pipeline commits
if echo "$COMMIT_MSG" | grep -qE '^release:|^chore\(release\):'; then
    exit 0
fi

# ============================================================================
# TASK ID EXTRACTION
# Supports:
#   1. Conventional commit scope: feat(T4541): description
#   2. Parenthesized suffix: description (T4541)
#   3. Bare reference: T4541 anywhere in message
# ============================================================================

TASK_ID=""

# Pattern 1: Conventional commit scope - type(T####):
if [[ -z "$TASK_ID" ]]; then
    TASK_ID=$(echo "$COMMIT_MSG" | grep -oE '^[a-z]+\(T[0-9]+\)' | head -1 | grep -oE 'T[0-9]+' || true)
fi

# Pattern 2: Parenthesized suffix - (T####) anywhere in message
if [[ -z "$TASK_ID" ]]; then
    TASK_ID=$(echo "$COMMIT_MSG" | grep -oE '\(T[0-9]+\)' | head -1 | grep -oE 'T[0-9]+' || true)
fi

# Pattern 3: Bare T#### reference anywhere in message (fallback)
if [[ -z "$TASK_ID" ]]; then
    TASK_ID=$(echo "$COMMIT_MSG" | grep -oE '\bT[0-9]{3,}\b' | head -1 || true)
fi

# ============================================================================
# VALIDATION
# ============================================================================

if [[ -z "$TASK_ID" ]]; then
    echo "ERROR: No task ID in commit message"
    echo ""
    echo "Convention: Include T#### in commit message"
    echo "Examples:"
    echo "  feat(T2692): Add protocol checks"
    echo "  fix(T1234): Resolve validation bug"
    echo "  chore: Update deps (T5678)"
    echo ""
    echo "Bypass with: git commit --no-verify"
    exit 1
fi

# ============================================================================
# TASK EXISTENCE CHECK
# Queries .cleo/tasks.db directly (SQLite, canonical storage per ADR-006).
# Uses node:sqlite (Node 22+) as primary, sqlite3 CLI as fallback.
# ============================================================================

TASKS_DB=".cleo/tasks.db"

if [[ ! -f "$TASKS_DB" ]]; then
    echo "WARNING: $TASKS_DB not found, skipping task existence check"
    echo "✓ Commit linked to $TASK_ID (unverified)"
    exit 0
fi

validate_task() {
    local task_id="$1"

    # Primary: node:sqlite (available in Node 22+, same engine as CLEO core)
    if command -v node &>/dev/null; then
        local result
        result=$(node -e "
            try {
                const { DatabaseSync } = require('node:sqlite');
                const db = new DatabaseSync('$TASKS_DB', { open: true, readOnly: true });
                const row = db.prepare('SELECT id FROM tasks WHERE id = ?').get('$task_id');
                console.log(row ? 'found' : 'not_found');
                db.close();
            } catch { console.log('error'); }
        " 2>/dev/null) || true
        if [[ "$result" == "found" ]]; then
            return 0
        fi
        if [[ "$result" == "not_found" ]]; then
            return 1
        fi
    fi

    # Fallback: sqlite3 CLI
    if command -v sqlite3 &>/dev/null; then
        local count
        count=$(sqlite3 "$TASKS_DB" "SELECT COUNT(*) FROM tasks WHERE id = '$task_id';" 2>/dev/null) || true
        if [[ "$count" -gt 0 ]] 2>/dev/null; then
            return 0
        fi
        if [[ "$count" == "0" ]]; then
            return 1
        fi
    fi

    # No SQLite reader available — warn but allow
    echo "WARNING: Cannot read $TASKS_DB (need node 22+ or sqlite3 CLI)"
    return 0
}

if ! validate_task "$TASK_ID"; then
    echo "ERROR: Task $TASK_ID not found in CLEO database"
    echo ""
    echo "Use: cleo find <query> to discover valid task IDs"
    echo "Or bypass with: git commit --no-verify"
    exit 1
fi

echo "✓ Commit linked to $TASK_ID"
exit 0
