#!/usr/bin/env bash
#
# PMAT TDG Enforcement Pre-Commit Hook
# Auto-generated by `pmat hooks install --tdg-enforcement`
# DO NOT EDIT MANUALLY - Regenerate with `pmat hooks refresh`
#
# This hook enforces quality gates before allowing commits:
# - Checks for quality regressions against baseline
# - Enforces minimum quality grades for new/modified files
# - Blocks commits that violate configured thresholds
#
# Configuration: .pmat/tdg-rules.toml

set -e  # Exit on first error

# ZERO BRANCHING ENFORCEMENT (runs FIRST, before all other checks)
# shellcheck disable=SC2154 (BASH_SOURCE is set by bash)
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
if [ -x "${SCRIPT_DIR}/pre-commit-branch-enforcer" ]; then
    "${SCRIPT_DIR}/pre-commit-branch-enforcer"
fi

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Configuration (injected by pmat hooks install)
BASELINE_PATH="{{BASELINE_PATH}}"
MIN_GRADE="{{MIN_GRADE}}"
MAX_SCORE_DROP="{{MAX_SCORE_DROP}}"
ALLOW_GRADE_DROP="{{ALLOW_GRADE_DROP}}"
MODE="{{MODE}}"
BLOCK_ON_REGRESSION="{{BLOCK_ON_REGRESSION}}"
BLOCK_ON_NEW_FILES="{{BLOCK_ON_NEW_FILES}}"

# cargo fmt --check on staged .rs files only (PMAT-509).
# Fast path: rustfmt is ~1ms/file so even large diffs check quickly.
# Skip silently if rustfmt is missing — CI will still catch format drift.
if command -v rustfmt >/dev/null 2>&1; then
    STAGED_RS=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null | grep '\.rs$' || true)
    if [ -n "${STAGED_RS}" ]; then
        UNFORMATTED=""
        for f in ${STAGED_RS}; do
            [ -f "${f}" ] || continue
            if ! rustfmt --check --edition 2021 "${f}" >/dev/null 2>&1; then
                UNFORMATTED="${UNFORMATTED}${f}\n"
            fi
        done
        if [ -n "${UNFORMATTED}" ]; then
            echo -e "${RED}❌ cargo fmt check failed on staged files:${NC}"
            printf "   %b" "${UNFORMATTED}"
            echo -e "${YELLOW}Fix with:${NC}  cargo fmt --all"
            echo -e "${YELLOW}Bypass:${NC}    git commit --no-verify  (not recommended)"
            exit 1
        fi
    fi
fi

echo -e "${BLUE}🔍 PMAT TDG Quality Enforcement${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# Check if TDG enforcement is disabled
if [ "${MODE}" = "disabled" ]; then
    echo -e "${YELLOW}⚠️  TDG enforcement disabled in config${NC}"
    exit 0
fi

# Check if pmat binary is available
if ! command -v pmat &> /dev/null; then
    echo -e "${RED}❌ Error: pmat binary not found in PATH${NC}"
    echo "   Install pmat: cargo install pmat"
    exit 1
fi

# Check if baseline exists
if [ ! -f "${BASELINE_PATH}" ]; then
    echo -e "${YELLOW}⚠️  No baseline found at ${BASELINE_PATH}${NC}"
    echo "   Creating initial baseline..."

    # Create parent directory if it doesn't exist (fixes issue #88)
    BASELINE_DIR="$(dirname "${BASELINE_PATH}")"
    # SEC010: Validate path doesn't contain traversal
    case "${BASELINE_DIR}" in
        *..* | /*)
            echo -e "${RED}❌ Invalid baseline path (traversal detected): ${BASELINE_DIR}${NC}"
            exit 1
            ;;
    esac
    if [ ! -d "${BASELINE_DIR}" ]; then
        mkdir -p "${BASELINE_DIR}" || {
            echo -e "${RED}❌ Failed to create directory: ${BASELINE_DIR}${NC}"
            exit 1
        }
    fi

    pmat tdg baseline create --output "${BASELINE_PATH}" --path .

    # shellcheck disable=SC2181
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}✅ Initial baseline created${NC}"
        echo "   Future commits will be checked against this baseline"
        exit 0
    fi
    echo -e "${RED}❌ Failed to create baseline${NC}"
    exit 1
fi

# Run regression check
echo ""
echo -e "${BLUE}📊 Checking for quality regressions...${NC}"

# Execute regression check
# Build command with conditional flags
REGRESSION_FLAGS="--baseline ${BASELINE_PATH} --path . --format table"
if [ -n "${MAX_SCORE_DROP}" ]; then
    REGRESSION_FLAGS="${REGRESSION_FLAGS} --max-score-drop ${MAX_SCORE_DROP}"
fi
if [ "${ALLOW_GRADE_DROP}" = "true" ]; then
    REGRESSION_FLAGS="${REGRESSION_FLAGS} --allow-grade-drop"
fi
if [ "${BLOCK_ON_REGRESSION}" = "true" ] && [ "${MODE}" = "strict" ]; then
    REGRESSION_FLAGS="${REGRESSION_FLAGS} --fail-on-regression"
fi

# shellcheck disable=SC2086 (intentional word splitting for flags)
if pmat tdg check-regression ${REGRESSION_FLAGS}; then
    echo -e "${GREEN}✅ No quality regressions detected${NC}"
else
    REGRESSION_EXIT=$?

    if [ "${MODE}" = "warning" ]; then
        echo -e "${YELLOW}⚠️  Quality regression detected (warning mode)${NC}"
        echo "   Commit allowed but please review quality issues"
    else
        echo -e "${RED}❌ Quality regression detected - commit blocked${NC}"
        echo ""
        echo "To fix:"
        echo "  1. Review quality issues above"
        echo "  2. Improve code quality to meet standards"
        echo "  3. Or update baseline if changes are intentional:"
        echo "     pmat tdg baseline update --output \"${BASELINE_PATH}\""
        echo ""
        echo "To bypass (NOT RECOMMENDED):"
        echo "  git commit --no-verify"
        exit "${REGRESSION_EXIT}"
    fi
fi

# Run quality check for new/modified files
echo ""
echo -e "${BLUE}📋 Checking quality of new/modified files...${NC}"

# Execute quality check
# Build command with conditional flags
QUALITY_FLAGS="--path . --format table --new-files-only --baseline ${BASELINE_PATH}"
if [ -n "${MIN_GRADE}" ]; then
    QUALITY_FLAGS="${QUALITY_FLAGS} --min-grade ${MIN_GRADE}"
fi
if [ "${BLOCK_ON_NEW_FILES}" = "true" ] && [ "${MODE}" = "strict" ]; then
    QUALITY_FLAGS="${QUALITY_FLAGS} --fail-on-violation"
fi

# shellcheck disable=SC2086 (intentional word splitting for flags)
if pmat tdg check-quality ${QUALITY_FLAGS}; then
    echo -e "${GREEN}✅ All new/modified files meet quality standards${NC}"
else
    QUALITY_EXIT=$?

    if [ "${MODE}" = "warning" ]; then
        echo -e "${YELLOW}⚠️  Quality violations detected (warning mode)${NC}"
        echo "   Commit allowed but please improve code quality"
    else
        echo -e "${RED}❌ Quality violations detected - commit blocked${NC}"
        echo ""
        echo "New/modified files must meet minimum grade: ${MIN_GRADE}"
        echo ""
        echo "To fix:"
        echo "  1. Improve code quality for files listed above"
        echo "  2. Reduce complexity, add documentation, remove duplication"
        echo ""
        echo "To bypass (NOT RECOMMENDED):"
        echo "  git commit --no-verify"
        exit "${QUALITY_EXIT}"
    fi
fi

# File health check (CB-040: max-lines enforcement)
# O(1) design: only checks staged .rs files, no index needed
echo ""
echo -e "${BLUE}📏 Checking file health (max-lines)...${NC}"

FILE_HEALTH_FAILED=0
STAGED_RS_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.rs$' || true)

if [ -n "$STAGED_RS_FILES" ]; then
    for file in $STAGED_RS_FILES; do
        if [ ! -f "$file" ]; then
            continue
        fi

        LINE_COUNT=$(wc -l < "$file")

        # Check if file is new (not yet tracked)
        if ! git ls-files --error-unmatch "$file" > /dev/null 2>&1; then
            # New file: hard block at >500 lines
            if [ "$LINE_COUNT" -gt 500 ]; then
                echo -e "${RED}❌ New file exceeds 500 lines: $file ($LINE_COUNT lines)${NC}"
                echo "   Split the file before committing. Use: pmat split $file"
                FILE_HEALTH_FAILED=1
            fi
        else
            # Existing file: strict ratchet (no growth allowed)
            BASELINE_COUNT=$(git show HEAD:"$file" 2>/dev/null | wc -l || echo "0")
            if [ "$LINE_COUNT" -gt "$BASELINE_COUNT" ] && [ "$BASELINE_COUNT" -gt 0 ]; then
                GROWTH=$((LINE_COUNT - BASELINE_COUNT))
                if [ "$LINE_COUNT" -gt 500 ]; then
                    echo -e "${RED}❌ File grew past 500-line limit: $file ($BASELINE_COUNT → $LINE_COUNT, +$GROWTH lines)${NC}"
                    echo "   Reduce file size or split. Use: pmat split $file"
                    FILE_HEALTH_FAILED=1
                elif [ "$LINE_COUNT" -gt 400 ]; then
                    echo -e "${YELLOW}⚠️  File approaching limit: $file ($LINE_COUNT lines, +$GROWTH)${NC}"
                fi
            fi
        fi
    done

    if [ $FILE_HEALTH_FAILED -eq 1 ]; then
        echo -e "${RED}❌ File health check failed - commit blocked${NC}"
        echo ""
        echo "To fix:"
        echo "  1. Split large files using: pmat split <file> --execute"
        echo "  2. Or reduce file size by extracting modules"
        echo ""
        echo "To bypass (NOT RECOMMENDED):"
        echo "  git commit --no-verify"
        exit 1
    fi

    echo -e "${GREEN}✅ File health check passed${NC}"
else
    echo "   No Rust files staged"
fi

# bashrs linting check (for bash scripts and Makefile)
echo ""
echo -e "${BLUE}🔍 Running bashrs linting on staged files...${NC}"

# Check if bashrs is installed
if ! command -v bashrs &> /dev/null; then
    echo -e "${YELLOW}⚠️  bashrs not found - skipping shell linting${NC}"
    echo "   Install bashrs: cargo install bashrs"
else
    # Get staged bash/Makefile files
    STAGED_SHELL_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(sh|bash)$|^Makefile$' || true)

    if [ -n "$STAGED_SHELL_FILES" ]; then
        BASHRS_FAILED=0
        for file in $STAGED_SHELL_FILES; do
            if [ -f "$file" ]; then
                echo "   Linting: $file"
                if ! bashrs lint "$file" 2>&1 | grep -q "0 error(s)"; then
                    # bashrs found errors - block commit
                    echo -e "${RED}❌ bashrs found errors in $file${NC}"
                    BASHRS_FAILED=1
                else
                    # Check for warnings (allowed but displayed)
                    WARNING_COUNT=$(bashrs lint "$file" 2>&1 | grep -o '[0-9]* warning(s)' | grep -o '[0-9]*' | head -1)
                    if [ -n "$WARNING_COUNT" ] && [ "$WARNING_COUNT" -gt 0 ]; then
                        echo -e "${YELLOW}   ⚠️  $WARNING_COUNT warning(s) (commit allowed)${NC}"
                    else
                        echo -e "   ✅ No issues"
                    fi
                fi
            fi
        done

        if [ $BASHRS_FAILED -eq 1 ]; then
            echo -e "${RED}❌ bashrs linting failed - commit blocked${NC}"
            echo ""
            echo "To fix:"
            echo "  1. Review bashrs errors above"
            echo "  2. Fix shell script issues"
            echo ""
            echo "To bypass (NOT RECOMMENDED):"
            echo "  git commit --no-verify"
            exit 1
        fi

        echo -e "${GREEN}✅ bashrs linting passed${NC}"
    else
        echo "   No bash/Makefile files staged"
    fi
fi

# All checks passed
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e "${GREEN}✅ All quality gates passed (TDG + bashrs)${NC}"
echo ""

exit 0
