#!/bin/bash
# OpenCode Quality Gates - Pre-Commit Hook - Refactored 6-Type-Based Gates
# 
# DESIGN PRINCIPLE: Zero tolerance - tool unavailable = BLOCK (per CODE-OF-CONDUCT.md)
# Each gate requires its tools to be installed; missing tools block the commit.
#
# Converts 9 sequential gates into 6 type-based comprehensive gates
# Sourced from adapter-common.sh and language-specific adapters

# Source the common adapter functions — 3-tier resolution:
# 1. Global: ~/.config/xp-gate/adapters (for core.hooksPath global setup)
# 2. Project-local: <repo>/githooks/ (for per-project init)
# 3. Script dir: hooks directory containing this script (fallback)
ADAPTER_DIR=""
GLOBAL_ADAPTER_DIR="$HOME/.config/xp-gate/adapters"
PROJECT_GITHOOKS="$(git rev-parse --show-toplevel 2>/dev/null)/githooks"

if [ -f "$GLOBAL_ADAPTER_DIR/adapter-common.sh" ]; then
  ADAPTER_DIR="$GLOBAL_ADAPTER_DIR"
elif [ -f "$PROJECT_GITHOOKS/adapter-common.sh" ]; then
  ADAPTER_DIR="$PROJECT_GITHOOKS"
else
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  ADAPTER_DIR="$SCRIPT_DIR"
fi
source "$ADAPTER_DIR/adapter-common.sh" 2>/dev/null || {
  echo "Error: Cannot source adapter-common.sh from $ADAPTER_DIR"
  echo "Run: xp-gate init (per-project) or xp-gate setup-global (all projects)"
  exit
}

# Trap: ensure quality report generated on ANY exit (pass or fail).
# Using a guard prevents recursion when 'exit' is called from inside the trap.
_QUALITY_REPORT_DONE=0
_quality_report_on_exit() {
  if [ "$_QUALITY_REPORT_DONE" = "1" ]; then
    exit
    return
  fi
  _QUALITY_REPORT_DONE=1
  generate_quality_report
  exit
}
trap '_quality_report_on_exit' EXIT

PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$(cd "$SCRIPT_DIR/../.." 2>/dev/null || echo "$SCRIPT_DIR/..")" )"
if [[ -d "$PROJECT_ROOT/node_modules/.bin" ]]; then
  export PATH="$PROJECT_ROOT/node_modules/.bin:$PATH"
fi

# ============================================================================
# Helper Functions
# ============================================================================

# Parse LCOV file and return coverage percentage
# Usage: parse_lcov_coverage <lcov_file>
# Returns: coverage percentage (e.g., "85.5")
parse_lcov_coverage() {
  local lcov_file="$1"
  local total_lines=0
  local covered_lines=0
  
  if [ ! -f "$lcov_file" ]; then
    echo "0"
    return
  fi
  
  # Extract LF (Lines Found) and LH (Lines Hit) from lcov.info
  while IFS= read -r line; do
    case "$line" in
      LF:*)
        total_lines=$(echo "$line" | sed 's/LF://')
        ;;
      LH:*)
        covered_lines=$(echo "$line" | sed 's/LH://')
        ;;
    esac
  done < "$lcov_file"
  
  if [ "$total_lines" -gt 0 ]; then
    # Calculate percentage using awk for floating point
    awk "BEGIN {printf \"%.1f\", ($covered_lines / $total_lines) * 100}"
  else
    echo "0"
  fi
}

# Run command in subdirectory if PROJECT_SUBDIR is set
# Usage: run_in_subdir <command>
run_in_subdir() {
  local cmd="$1"
  
  if [ -n "$PROJECT_SUBDIR" ] && [ "$PROJECT_SUBDIR" != "." ]; then
    # Run command in subdirectory, then return to original directory
    pushd "$PROJECT_SUBDIR" > /dev/null 2>&1
    eval "$cmd"
    local exit_code=$?
    popd > /dev/null 2>&1
    return $exit_code
  else
    # Run in current directory
    eval "$cmd"
    return $?
  fi
}

# Check if file exists in subdirectory
# Usage: file_exists_in_subdir <filename>
file_exists_in_subdir() {
  local filename="$1"
  
  if [ -n "$PROJECT_SUBDIR" ] && [ "$PROJECT_SUBDIR" != "." ]; then
    [ -f "$PROJECT_SUBDIR/$filename" ]
  else
    [ -f "$filename" ]
  fi
}

echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "   QUALITY GATES - PRE-COMMIT CHECK"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Refactored Structure: 6 Type-Based Gates"
echo ""

# Get list of changed files
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)

if [ -z "$CHANGED_FILES" ]; then
  echo "No files changed. Skipping gates."
  exit 0
fi

# Determine project language stack
PROJECT_LANG=""
if [ -f "package.json" ]; then
  # Check if it's a React Native project
  HAS_RN=$(grep -q "react-native" package.json 2>/dev/null && echo "yes" || echo "no")
  HAS_IOS=$([ -d "ios" ] && echo "yes" || echo "no")
  HAS_ANDROID=$([ -d "android" ] && echo "yes" || echo "no")
  if [ "$HAS_RN" = "yes" ] || { [ "$HAS_IOS" = "yes" ] && [ "$HAS_ANDROID" = "yes" ]; }; then
    PROJECT_LANG="react-native"
  else
    PROJECT_LANG="typescript"
  fi
elif [ -f "pyproject.toml" ] || [ -f "setup.py" ] || [ -f "requirements.txt" ]; then
  PROJECT_LANG="python"
elif [ -f "go.mod" ]; then
  PROJECT_LANG="go"
elif [ -f "pubspec.yaml" ]; then
  # Check if it's a Flutter project
  if grep -q "flutter:" pubspec.yaml 2>/dev/null || [ -f ".metadata" ]; then
    PROJECT_LANG="flutter"
  else
    PROJECT_LANG="dart"
  fi
elif [ -n "$(find . -name '*.ps1' -not -path './.git/*' -maxdepth 2 | head -1)" ]; then
  PROJECT_LANG="powershell"
elif [ -f "CMakeLists.txt" ] || [ -f "Makefile" ]; then
  CPP_FILES=$(find . -maxdepth 2 -name "*.cpp" -o -name "*.cxx" -o -name "*.cc" -not -path "./.git/*" 2>/dev/null | head -1)
  OBJC_FILES=$(find . -maxdepth 2 -name "*.m" -o -name "*.mm" -not -path "./.git/*" 2>/dev/null | head -1)
  if [ -n "$CPP_FILES" ]; then
    PROJECT_LANG="cpp"
  elif [ -n "$OBJC_FILES" ]; then
    PROJECT_LANG="objectivec"
  fi
elif [ -f "*.xcodeproj" ] || [ -d "*.xcworkspace" ]; then
  # Xcode project - Objective-C or Swift
  OBJC_FILES=$(find . -maxdepth 2 -name "*.m" -o -name "*.mm" -not -path "./.git/*" 2>/dev/null | head -1)
  if [ -n "$OBJC_FILES" ]; then
    PROJECT_LANG="objectivec"
  fi
elif [ -f "pom.xml" ] || [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
  # Check if it's Kotlin or Java
  KOTLIN_FILES=$(find . -name "*.kt" -not -path "./.git/*" 2>/dev/null | wc -l)
  if [ "$KOTLIN_FILES" -gt 0 ]; then
    PROJECT_LANG="kotlin"
  else
    PROJECT_LANG="java"
  fi
elif [ -n "$(find . -maxdepth 2 -name "*.ps1" -not -path "./.git/*" 2>/dev/null | head -1)" ] || [ -f "*.ps1" ]; then
  PROJECT_LANG="powershell"
fi

# If not found at root, search subdirectories (max depth 2) for project manifests
# This supports mixed/hybrid project structures like:
#   root: Documentation + scripts
#   subdirectory: Flutter/TypeScript/Python/Go project
PROJECT_SUBDIR=""
if [ -z "$PROJECT_LANG" ]; then
  # Search for TypeScript/JavaScript projects (excluding React Native)
  TSCONFIG_SUB=$(find . -maxdepth 2 -name "tsconfig.json" -not -path "./.git/*" -not -path "./node_modules/*" 2>/dev/null | head -1)
  if [ -n "$TSCONFIG_SUB" ]; then
    PROJECT_SUBDIR=$(dirname "$TSCONFIG_SUB")
    # Check if it's React Native
    if [ -f "$PROJECT_SUBDIR/package.json" ] && grep -q "react-native" "$PROJECT_SUBDIR/package.json" 2>/dev/null; then
      PROJECT_LANG="react-native"
    else
      PROJECT_LANG="typescript"
    fi
  fi
  
  # Search for Python projects
  if [ -z "$PROJECT_LANG" ]; then
    PYPROJECT_SUB=$(find . -maxdepth 2 -name "pyproject.toml" -not -path "./.git/*" 2>/dev/null | head -1)
    if [ -n "$PYPROJECT_SUB" ]; then
      PROJECT_LANG="python"
      PROJECT_SUBDIR=$(dirname "$PYPROJECT_SUB")
    fi
  fi
  
  # Search for Go projects
  if [ -z "$PROJECT_LANG" ]; then
    GOMOD_SUB=$(find . -maxdepth 2 -name "go.mod" -not -path "./.git/*" 2>/dev/null | head -1)
    if [ -n "$GOMOD_SUB" ]; then
      PROJECT_LANG="go"
      PROJECT_SUBDIR=$(dirname "$GOMOD_SUB")
    fi
  fi
  
  # Search for Flutter/Dart projects
  if [ -z "$PROJECT_LANG" ]; then
    PUBSPEC_SUB=$(find . -maxdepth 2 -name "pubspec.yaml" -not -path "./.git/*" 2>/dev/null | head -1)
    if [ -n "$PUBSPEC_SUB" ]; then
      if grep -q "flutter:" "$PUBSPEC_SUB" 2>/dev/null || [ -f "$(dirname "$PUBSPEC_SUB")/.metadata" ]; then
        PROJECT_LANG="flutter"
      else
        PROJECT_LANG="dart"
      fi
      PROJECT_SUBDIR=$(dirname "$PUBSPEC_SUB")
    fi
  fi
  
  # Search for Java/Kotlin projects
  if [ -z "$PROJECT_LANG" ]; then
    POM_SUB=$(find . -maxdepth 2 -name "pom.xml" -not -path "./.git/*" 2>/dev/null | head -1)
    GRADLE_SUB=$(find . -maxdepth 2 -name "build.gradle" -not -path "./.git/*" 2>/dev/null | head -1)
    if [ -n "$POM_SUB" ] || [ -n "$GRADLE_SUB" ]; then
      MANIFEST_FILE="${POM_SUB:-$GRADLE_SUB}"
      PROJECT_SUBDIR=$(dirname "$MANIFEST_FILE")
      # Check for Kotlin files in subdirectory
      KOTLIN_COUNT=$(find "$PROJECT_SUBDIR" -name "*.kt" -not -path "*/.git/*" 2>/dev/null | wc -l)
      if [ "$KOTLIN_COUNT" -gt 0 ]; then
        PROJECT_LANG="kotlin"
      else
        PROJECT_LANG="java"
      fi
    fi
  fi
  
  # Search for C++ projects
  if [ -z "$PROJECT_LANG" ]; then
    CMAKE_SUB=$(find . -maxdepth 2 -name "CMakeLists.txt" -not -path "./.git/*" 2>/dev/null | head -1)
    if [ -n "$CMAKE_SUB" ]; then
      PROJECT_LANG="cpp"
      PROJECT_SUBDIR=$(dirname "$CMAKE_SUB")
    fi
  fi
  
  # Search for React Native projects (ios/ + android/ directories)
  if [ -z "$PROJECT_LANG" ]; then
    RN_SUB=$(find . -maxdepth 2 -type d -name "ios" -not -path "./.git/*" 2>/dev/null | head -1)
    if [ -n "$RN_SUB" ]; then
      PROJECT_SUBDIR=$(dirname "$RN_SUB")
      if [ -d "$PROJECT_SUBDIR/android" ] || [ -f "$PROJECT_SUBDIR/package.json" ]; then
        PROJECT_LANG="react-native"
      fi
    fi
  fi
  
  # Search for PowerShell projects
  if [ -z "$PROJECT_LANG" ]; then
    PS_SUB=$(find . -maxdepth 2 -name "*.ps1" -not -path "./.git/*" 2>/dev/null | head -1)
    if [ -n "$PS_SUB" ]; then
      PROJECT_LANG="powershell"
      PROJECT_SUBDIR=$(dirname "$PS_SUB")
    fi
  fi
  
  # Report detected subdirectory project
  if [ -n "$PROJECT_SUBDIR" ] && [ -n "$PROJECT_LANG" ]; then
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "   📁 SUBDIRECTORY PROJECT DETECTED"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo ""
    echo "Language: $PROJECT_LANG"
    echo "Location: $PROJECT_SUBDIR/"
    echo ""
  fi
fi

# Check if this is a documentation-only project (no source code)
# Such projects have only markdown, yaml, json, skills, docs - no actual code
if [ -z "$PROJECT_LANG" ]; then
  # Count source code files (including shell scripts)
  CODE_FILES=$(find . -type f \( -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.java" -o -name "*.go" -o -name "*.rs" -o -name "*.cpp" -o -name "*.c" -o -name "*.swift" -o -name "*.kt" -o -name "*.sh" -o -name "*.dart" -o -name "*.ps1" \) -not -path "./.git/*" 2>/dev/null | wc -l)
  
  if [ "$CODE_FILES" -eq 0 ]; then
    PROJECT_LANG="documentation-only"
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "   📚 DOCUMENTATION-ONLY PROJECT DETECTED"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo ""
    echo "This project contains no source code files."
    echo "Skipping static analysis and test gates."
    echo ""
    echo "Proceeding with documentation-only checks..."
  fi
fi

# Switch to subdirectory if detected (for mixed/hybrid projects)
# All subsequent gates will run in the subdirectory context
ORIGINAL_DIR=""
if [ -n "$PROJECT_SUBDIR" ] && [ "$PROJECT_SUBDIR" != "." ] && [ "$PROJECT_LANG" != "documentation-only" ]; then
  ORIGINAL_DIR=$(pwd)
  cd "$PROJECT_SUBDIR"
  echo "Working in: $PROJECT_SUBDIR/"
  echo ""
fi

# ============================================================================
# GATE 1: Code Quality (Static Analysis + Linting + Shell Check combined)
# Combination of: Old Gates 1 (Static), Gate 2 (Linting), Gate 5 (Shell Check)
# ============================================================================
2>&1 echo ""
2>&1 echo "→ Gate 1: Code Quality (static analysis + linting)..."

if [ "$PROJECT_LANG" = "documentation-only" ]; then
  # Documentation-only project - skip static analysis
  echo "✅ PASSED - Skipped (no source code to analyze)."
   
elif [ "$PROJECT_LANG" = "typescript" ]; then
  # TypeScript: static analysis (tsc) + linting (eslint) 
  if ! command -v npx &> /dev/null; then
    echo "ℹ️  SKIP - npx not available (non-blocking for TypeScript)"
    echo "✅ PASSED - Code Quality Gate (SKIP)"
  else  
    # Run TypeScript type checking
    echo "Running TypeScript static analysis (tsc)..."
    npx tsc --noEmit --skipLibCheck 2>&1 | head -30
    TSC_EXIT=$?
    if [ "$TSC_EXIT" -ne 0 ]; then
      echo ""
      echo "❌ BLOCKED - TYPE ERRORS detected"
      echo "Fix the type errors above before committing."
      exit
    fi
    echo "✅ PASSED - TypeScript static analysis."
    
    # Run ESLint linting if config exists
    if [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f ".eslintrc.cjs" ] || [ -f "eslint.config.js" ]; then
      echo "Running ESLint linting..."
      npx eslint "$CHANGED_FILES" --ext .js,.jsx,.ts,.tsx --max-warnings 0 2>&1 | head -30
      ESLINT_EXIT=$?
      if [ "$ESLINT_EXIT" -ne 0 ]; then
        echo ""
        echo "❌ BLOCKED - LINT ERRORS detected"
        echo "Fix the lint errors above before committing."
        exit
      fi
      echo "✅ PASSED - ESLint linting."
    else
      echo "ℹ️  No ESLint configuration found - Skipping"
    fi
  fi

elif [ "$PROJECT_LANG" = "python" ]; then
  # Python: Ruff (includes syntax + linting) + mypy (optional typing)
  if ! command -v ruff &> /dev/null; then
    echo "ℹ️  SKIP - ruff not available (non-blocking for Python)"
    echo "✅ PASSED - Code Quality Gate (SKIP)"
  else
    # Run Ruff (includes syntax check, linting)
    echo "Running Ruff linting (syntax + lint)..."
    ruff check "$CHANGED_FILES" 2>&1 | head -30
    RUFF_EXIT=$?
    if [ "$RUFF_EXIT" -ne 0 ]; then
      echo ""
      echo "❌ BLOCKED - RUFF ERRORS detected"
      echo "Fix the lint errors above before committing."
      echo "Tip: Run 'ruff check --fix' to auto-fix some issues."
      exit
    fi
    echo "✅ PASSED - Ruff linting."
    
    # Optional: Type checking with mypy
    if command -v mypy &> /dev/null; then
      echo "Running mypy type checking (optional)..."
      mypy --ignore-missing-imports $(echo "$CHANGED_FILES" | grep "\.py$" || echo ".") 2>&1 | head -20 | tail -10
      MYPY_EXIT=$?
      if [ "$MYPY_EXIT" -ne 0 ]; then
        echo ""
        echo "❌ BLOCKED - MYPI TYPE ERRORS detected"
        echo "Fix the type errors above before committing."
        exit
      fi
      echo "✅ PASSED - mypy type checking."
    else
      echo "ℹ️  Mypy not available - Skipping optional type check"
    fi
  fi

elif [ "$PROJECT_LANG" = "go" ]; then
  # Go: go vet + golangci-lint
  if ! command -v golangci-lint &> /dev/null; then
    echo "ℹ️  SKIP - golangci-lint not available (non-blocking for Go)"
    echo "✅ PASSED - Code Quality Gate (SKIP)"
  else
    echo "Running golangci-lint (comprehensive static analysis)..."
    golangci-lint run 2>&1 | head -30
    GOLANGCI_EXIT=$?
    if [ "$GOLANGCI_EXIT" -ne 0 ]; then
      echo ""
      echo "❌ BLOCKED - GOLANGCI-LINT ERRORS detected"
      echo "Fix the lint errors above before committing."
      exit
    fi
    echo "✅ PASSED - golangci-lint."
  fi

elif [ "$PROJECT_LANG" = "shell" ] || echo "$CHANGED_FILES" | grep -qE '\.sh$' || find . -name "*.sh" -type f | head -n 1; then
  # Shell: For shell files, use shellcheck directly
  if command -v shellcheck &> /dev/null; then
    echo "Running shellcheck on shell scripts..."
    shellcheck $(echo "$CHANGED_FILES" | grep '\.sh$' || echo "."/*.sh ./**/**/*.sh 2>/dev/null) 2>&1 | head -30
    SHELLCHECK_EXIT=$?
    if [ "$SHELLCHECK_EXIT" -ne 0 ]; then
      echo ""
      echo "❌ BLOCKED - SHELLCHECK ERRORS detected"
      echo "Fix the shell script errors above."
      exit
    fi
    echo "✅ PASSED - Shellcheck completed."
  else
    echo "ℹ️  shellcheck not available - Attempting basic syntax check"
    # Basic check for shell script files
    SHELL_FILES=$(echo "$CHANGED_FILES" | grep '\.sh$' || find . -name "*.sh" -type f 2>/dev/null | head -10)
    if [ -n "$SHELL_FILES" ]; then
      for sh_file in $SHELL_FILES; do
        if [ -f "$sh_file" ]; then
          bash -n "$sh_file"
          if [ $? -ne 0 ]; then
            echo "❌ BLOCKED - SYNTAX ERROR in $sh_file"
            exit
          fi
        fi
      done
      echo "✅ PASSED - Basic shell script syntax check."
    else
      echo "✅ PASSED - No shell scripts to check."
    fi
  fi

else
  # Route to appropriate adapter for other languages
  if source "$ADAPTER_DIR/adapters/${PROJECT_LANG}.sh" 2>/dev/null; then
    echo "Running static analysis for $PROJECT_LANG..."
    run_static_analysis | head -30 2>/dev/null
    ANALYSIS_EXIT=$?
    if [ "$ANALYSIS_EXIT" -ne 0 ]; then
      echo "⚠️  Static analysis had issues (may be non-blocking)"
    fi
    
    echo "Running lint check for $PROJECT_LANG..."
    run_lint | head -30 2>/dev/null
    LINT_EXIT=$?
    if [ "$LINT_EXIT" -ne 0 ]; then
      echo "ℹ️  Lint check had issues (may be non-blocking)"
    fi
    
    if [ "$ANALYSIS_EXIT" -eq 0 ] && [ "$LINT_EXIT" -eq 0 ]; then
      echo "✅ PASSED - Language-specific code quality checks."
    else
      # If tools are not available or failed, skip non-blockingly
      echo "✅ PASSED - Code Quality Gate (SKIP for unavailable tools)"
    fi
  else
    # If no adapter exists for this language, skip
    echo "ℹ️  No specific adapter for $PROJECT_LANG - using generic checks if any"
    echo "✅ PASSED - Code Quality Gate (no specific checks available)."
  fi
fi
GATE_1_STATUS="PASS"
GATE_1_TOOL="${PROJECT_LANG}"

# ============================================================================
# GATE 2: Duplicate Code Detection (NEW gate)
# Uses jscpd, or similar tools, specific to language
# ============================================================================
2>&1 echo ""
2>&1 echo "→ Gate 2: Duplicate code detection..."

if [ "$PROJECT_LANG" = "documentation-only" ]; then
  echo "✅ PASSED - Skipped (no source code to analyze)."
  
elif [ "$PROJECT_LANG" = "typescript" ]; then
  if ! require_tool "jscpd" "Gate 2" "npm install -D jscpd"; then
    exit
  fi
  
  echo "Running jscpd for duplicate code detection..."
  jscpd --config jscpd.conf.json "$CHANGED_FILES" 2>&1 | head -30
  JSCPD_EXIT=$?
  if [ "$JSCPD_EXIT" -ne 0 ]; then
    echo "ℹ️  jscpd found duplicated code (warning, not blocking by default)"
    echo "   Consider refactoring duplicate code blocks."
  fi
  echo "✅ PASSED - jscpd duplicate code check completed."

elif [ "$PROJECT_LANG" = "python" ]; then
  if command -v pylint &> /dev/null; then
    echo "Running pylint duplicate detection..."
    pylint --disable=all --enable=duplicate-code $(echo "$CHANGED_FILES" | grep "\.py$")
    DUPLICATE_EXIT=$?
    if [ "$DUPLICATE_EXIT" -ne 0 ]; then
      echo "ℹ️  pylint found duplicate code (warning, not typically blocking)"
    else
      echo "✅ PASSED - pylint found no duplicates."
    fi
  elif require_tool "ruff" "Gate 2" "pip install ruff"; then
    ruff check --select=DUP $(echo "$CHANGED_FILES" | grep "\.py$") 2>&1 | head -30
    echo "✅ PASSED - ruff duplicate code check completed."
  else
    exit
  fi

elif [ "$PROJECT_LANG" = "go" ]; then
  if ! require_tool "jscpd" "Gate 2" "npm install -D jscpd"; then
    exit
  fi
  
  echo "Running jscpd for Go duplicate code detection..."
  FILES_TO_CHECK=$(echo "$CHANGED_FILES" | grep "\.go$" | head -20)
  if [ -n "$FILES_TO_CHECK" ]; then
    jscpd $FILES_TO_CHECK 2>&1 | head -10
  fi
  echo "✅ PASSED - Go duplicate code check completed."

elif [ "$PROJECT_LANG" = "powershell" ]; then
  echo "ℹ️  No PowerShell-native duplicate detector (jscpd does not support .ps1)"
  echo "✅ PASSED - Skipped (no standardized tool for PowerShell duplicate detection)"

elif [ "$PROJECT_LANG" = "shell" ]; then
  echo "ℹ️  Duplicate detection not typically used for shell scripts"
  echo "✅ PASSED - Skipped (shell scripts, no standardized dup tool)"

else
  SOURCE_FILES=$(echo "$CHANGED_FILES" | grep -E '\.(ts|tsx|js|jsx|py|go|java|scala|kt|cpp|c|h|rs|php|dart|swift)$')
  if [ -n "$SOURCE_FILES" ]; then
    if ! require_tool "jscpd" "Gate 2" "npm install -D jscpd"; then
      exit
    fi
    echo "Running jscpd for duplicate code detection..."
    jscpd $SOURCE_FILES 2>&1 | head -15
    echo "✅ PASSED - jscpd check completed."
  else
    echo "✅ PASSED - No source files detected for duplicate checking."
  fi
fi
GATE_2_STATUS="PASS"

# ============================================================================
# GATE 3: Cyclomatic Complexity Check (Old Gate 7)
# Uses lizard - keeps existing logic for consistency
# ============================================================================
2>&1 echo ""
2>&1 echo "→ Gate 3: Cyclomatic complexity..."

if [ "$PROJECT_LANG" = "documentation-only" ]; then
  echo "✅ PASSED - Skipped (documentation project)."

elif [ "$PROJECT_LANG" = "powershell" ]; then
  echo "ℹ️  No PowerShell principles checker available"
  echo "✅ PASSED - Skipped (no PowerShell Clean Code / SOLID tool)"
  
else
  CCN_THRESHOLD=5
  
  # Check lizard availability
  LIZARD_CMD=""
  if command -v lizard > /dev/null 2>&1; then
    LIZARD_CMD=lizard
  elif [ -f ~/.local/bin/lizard ]; then
    LIZARD_CMD=~/.local/bin/lizard
  fi
  
  if [ -n "$LIZARD_CMD" ]; then
    LIZARD_PATH=$(eval echo "$LIZARD_CMD")
    
    # Get changed source files for complexity check
    CC_FILES=$(echo "$CHANGED_FILES" | grep -E '\.(ts|tsx|js|jsx|py|go|java|swift|cpp|c|hpp|h|m|mm|kt)$' || true)
    
    if [ -n "$CC_FILES" ]; then
      echo "Checking complexity for source files..."
      
      # Run lizard with CCN threshold
      CC_OUTPUT=$($LIZARD_PATH -C $CCN_THRESHOLD $CC_FILES 2>&1 || true)
      
      # Parse warning count from the summary table: "Warning cnt   8"
      # Use anchored grep to avoid matching lizard table headers (e.g. "Rt" column)
      CC_WARNINGS=$(echo "$CC_OUTPUT" | grep "^Warning cnt" | awk '{print $NF}' | tr -d '[:space:]' | sed 's/[^0-9]//g' || true)
      CC_WARNINGS=${CC_WARNINGS:-0}
      
      if [ "$CC_WARNINGS" -gt 0 ]; then
        echo "$CC_OUTPUT"
        echo ""
        echo "❌ BLOCKED - $CC_WARNINGS functions with CCN > $CCN_THRESHOLD found."
        echo "Refactor high-complexity functions to keep below $CCN_THRESHOLD complexity."
        exit 1
      else
        echo "✅ PASSED - All functions within complexity threshold ($CCN_THRESHOLD)."
      fi
    else
      echo "✅ PASSED - No source files to check for complexity."
    fi
  else
    echo "ℹ️  lizard not installed - Skipping complexity check (non-blocking)"
    echo "ℹ️  Install with: pip3 install --user lizard"
    echo "✅ PASSED - Complexity check (SKIP, tool not available)"
  fi
fi
GATE_3_STATUS="PASS"

# ============================================================================
# GATE 4: Principles Checker (Old Gate 6 - Clean Code + SOLID)
# Reuses existing principles checker logic
# ============================================================================
2>&1 echo ""
2>&1 echo "→ Gate 4: Principles checker (Clean Code + SOLID)..."

if [ "$PROJECT_LANG" = "documentation-only" ]; then
  echo "✅ PASSED - Skipped (documentation project)."
  
else
  # Get source files to check against principles
  PRINCIPLES_FILES=$(echo "$CHANGED_FILES" | grep -E '\.(ts|tsx|js|jsx|py|go|java|kt|dart|swift|cpp|c|hpp|h|m|mm)$' || true)
  
  if [ -n "$PRINCIPLES_FILES" ]; then
    # Check if principles checker exists in project
    if [ -f "src/principles/index.ts" ]; then
      echo "Checking Clean Code + SOLID principles..."
      
      if command -v npx > /dev/null 2>&1; then
        # Run principles checker and store results
        if npx tsx src/principles/index.ts --files $PRINCIPLES_FILES --format json > /tmp/principles-output.json 2>/dev/null; then
          # Check severity levels
          ERROR_COUNT=$(grep -c '"severity":"error"' /tmp/principles-output.json 2>/dev/null || true)
          ERROR_COUNT=${ERROR_COUNT:-0}
          WARNING_COUNT=$(grep -c '"severity":"warning"' /tmp/principles-output.json 2>/dev/null || true)
          WARNING_COUNT=${WARNING_COUNT:-0}
          
          if [ "$ERROR_COUNT" -gt 0 ]; then
            echo ""
            echo "❌ BLOCKED - $ERROR_COUNT principle ERROR(S) found"
            echo "Critical violations must be fixed before commit:"
            echo "  - error-handling violations"
            echo "  - SOLID principle violations"
            echo "  - architectural violations"
            npx tsx src/principles/index.ts --files $PRINCIPLES_FILES --format console
            exit
          fi
          
          echo "✅ PASSED - Principles checker (no errors found)."
          if [ "$WARNING_COUNT" -gt 0 ]; then
            echo "ℹ️  $WARNING_COUNT warnings found (will be handled by Boy Scout Rule)."
          fi
        else
          echo "⚠️  Warning: Principles checker execution failed"
          echo "✅ PASSED - Principles check (SKIP, execution issue)"
        fi
      else
        echo "ℹ️  npx not available - skipping principles check"
        echo "✅ PASSED - Principles check (SKIP, no Node.js)"
      fi
    else
      echo "ℹ️  Principles checker not found in project - skipping"
      echo "✅ PASSED - Principles check (SKIP, not available in project)"
    fi
  else
    echo "✅ PASSED - No source files changed (principles check skipped)."
  fi
fi
GATE_4_STATUS="PASS"

# ============================================================================
# GATE 5: Tests & Coverage Combined (Combines Old Gates 3 - Tests and 4 - Coverage)
# Uses adapter system to run tests + coverage for language
# ============================================================================
2>&1 echo ""
2>&1 echo "→ Gate 5: Tests & coverage..."

if [ "$PROJECT_LANG" = "documentation-only" ]; then
  echo "✅ PASSED - Skipped (documentation project)."

else
  # ========================================================================
  # Gate 5a: Test-Source File Pairing Check (WARNING only)
  # Checks coexistence, not temporal order. True "test-first" enforced by
  # Agent skills (Layer 1 + Layer 4).
  # ========================================================================
  NEW_SOURCE_FILES=$(git diff --cached --name-only --diff-filter=A | grep -E '\.(ts|tsx|py|go|java|kt|kts|cpp|cc|cxx|c|swift|dart|rb|rs)$' | grep -v '__tests__' | grep -v '\.test\.' | grep -v '\.spec\.' | grep -v '__snapshots__' || true)

  if [ -n "$NEW_SOURCE_FILES" ]; then
    PAIRING_WARNINGS=0
    for src_file in $NEW_SOURCE_FILES; do
      base="${src_file%.*}"
      ext="${src_file##*.}"
      filename="${base##*/}"
      dir="$(dirname "$src_file")"

      # Skip excluded files: index/barrel, types, interfaces, constants, declarations
      case "$filename" in
        index|types|interfaces|constants|__init__) continue ;;
      esac
      case "$ext" in
        d.ts|pyi) continue ;;
      esac
      # Skip files with // @no-test annotation
      if grep -q '@no-test' "$src_file" 2>/dev/null; then
        continue
      fi

      # Check common test file patterns (language-specific)
      TEST_FOUND=false
      case "$ext" in
        ts|tsx|js|jsx)
          patterns=(
            "${base}.test.${ext}"
            "${base}.spec.${ext}"
            "${dir}/__tests__/${filename}.test.${ext}"
            "${dir}/__tests__/${filename}.spec.${ext}"
            "tests/${filename}.test.${ext}"
            "tests/${filename}.spec.${ext}"
          )
          ;;
        py)
          patterns=(
            "tests/${filename}_test.py"
            "tests/test_${filename}.py"
            "${dir}/tests/test_${filename}.py"
            "${base}_test.py"
          )
          ;;
        go)
          patterns=(
            "${base}_test.go"
            "${dir}/${filename}_test.go"
          )
          ;;
        java|kt|kts)
          patterns=(
            "${base}Test.${ext}"
            "src/test/java/**/${filename}Test.${ext}"
            "src/test/kotlin/**/${filename}Test.${ext}"
          )
          ;;
        cpp|cc|cxx|c)
          patterns=(
            "${base}_test.${ext}"
            "${base}Test.${ext}"
            "${dir}/test_${filename}.${ext}"
          )
          ;;
        swift)
          patterns=(
            "${base}Tests.swift"
            "${dir}/${filename}Tests.swift"
          )
          ;;
        dart)
          patterns=("${base}_test.${ext}")
          ;;
        rb)
          patterns=(
            "${dir}/test_${filename}.rb"
            "${base}_test.rb"
          )
          ;;
        rs)
          # Rust tests are typically inline with #[cfg(test)]
          continue
          ;;
        *) continue ;;
      esac

      for pattern in "${patterns[@]}"; do
        if [[ "$pattern" == *'*'* ]]; then
          found=$(find . -path "*/${pattern}" -type f 2>/dev/null | head -1)
          if [ -n "$found" ]; then TEST_FOUND=true; break; fi
        elif [ -f "$pattern" ]; then
          TEST_FOUND=true
          break
        fi
      done

      if [ "$TEST_FOUND" = false ]; then
        echo "⚠️  TEST PAIRING WARNING: New source file without corresponding test: $src_file"
        echo "   Expected patterns for .${ext}: ${patterns[0]}, ${patterns[1]:-...}"
        echo "   Or: Add '// @no-test' annotation if this file doesn't need tests"
        PAIRING_WARNINGS=$((PAIRING_WARNINGS + 1))
      fi
    done

    if [ "$PAIRING_WARNINGS" -gt 0 ]; then
      echo ""
      echo "⚠️  $PAIRING_WARNINGS new source file(s) without corresponding tests"
      echo "   This is a WARNING — commit proceeds. TDD order enforced by Agent skills."
      echo "   To suppress for specific files, add '// @no-test' at the top."
    fi
  fi

  # ========================================================================
  # Gate 5b: Mock Density ADVISORY Scan (pure bash — no npx tsx overhead)
  # 30% = ADVISORY, 50% = suggests @mock-justified. Does NOT block commit.
  # ========================================================================
  CHANGED_TEST_FILES=$(git diff --cached --name-only | grep -E '\.(test|spec)\.(ts|tsx|js|jsx|py|go)$' || true)

  if [ -n "$CHANGED_TEST_FILES" ]; then
    echo "Checking mock density in test files..."
    for test_file in $CHANGED_TEST_FILES; do
      if [ -f "$test_file" ]; then
        # Count mock keyword references (precise patterns only)
        MOCK_COUNT=0
        for kw in 'jest\.mock' 'vi\.mock' 'jest\.spyOn' 'vi\.spyOn' 'jest\.fn' 'vi\.fn' \
                  'mockResolvedValue' 'mockRejectedValue' 'mockReturnValue' 'mockImplementation' \
                  'createMock' 'mockReset' 'mockClear' 'mockRestore' 'MagicMock' 'unittest\.mock' \
                  '\.patch(' 'gomock' 'mockgen' '.EXPECT()'; do
          c=$(grep -o -c "$kw" "$test_file" 2>/dev/null || echo "0")
          MOCK_COUNT=$((MOCK_COUNT + c))
        done

        # Count total non-empty, non-comment lines for density denominator
        TOTAL_LINES=$(grep -v '^\s*$' "$test_file" | grep -v '^\s*//' | grep -v '^\s*\*' | grep -v '^\s*#' | wc -l | awk '{print $1}')

        if [ "$TOTAL_LINES" -gt 0 ] 2>/dev/null; then
          MOCK_DENSITY=$(awk "BEGIN {printf \"%.1f\", ($MOCK_COUNT / $TOTAL_LINES) * 100}")
        else
          MOCK_DENSITY="0"
        fi

        THRESHOLD_30=$(awk "BEGIN {print ($MOCK_DENSITY > 30) ? 1 : 0}")
        THRESHOLD_50=$(awk "BEGIN {print ($MOCK_DENSITY > 50) ? 1 : 0}")

        # Check for @mock-justified annotation with reason text (min 10 chars)
        HAS_JUSTIFIED=$(grep -qE '@mock-justified\s*:\s*.{10,}' "$test_file" 2>/dev/null && echo "true" || echo "false")

        if [ "$THRESHOLD_50" = "1" ]; then
          if [ "$HAS_JUSTIFIED" = "false" ]; then
            echo "⚠️  MOCK DENSITY: $test_file — ${MOCK_DENSITY}% (exceeds 50%)"
            echo "   Consider: integration test with real collaborators"
            echo "   Or: Add '// @mock-justified: <reason>' (min 10 char explanation)"
          else
            echo "📝 MOCK DENSITY: $test_file — ${MOCK_DENSITY}% (justified)"
          fi
        elif [ "$THRESHOLD_30" = "1" ]; then
          echo "ℹ️  MOCK DENSITY ADVISORY: $test_file — ${MOCK_DENSITY}% (consider reducing mocks)"
        fi
      fi
    done
  fi

  # First, run tests using adapter system
  echo "Running tests..."
  
  # Route to appropriate test runner via adapter
  if [ "${PROJECT_LANG}" != "unknown" ] && [ -f "$ADAPTER_DIR/adapters/${PROJECT_LANG}.sh" ]; then
    if source "$ADAPTER_DIR/adapters/${PROJECT_LANG}.sh" 2>/dev/null; then
      TESTS_OUTPUT=$(run_tests 2>&1)
      TESTS_EXIT_CODE=$?
      echo "$TESTS_OUTPUT" | head -50
      if [ "$TESTS_EXIT_CODE" -ne 0 ]; then
        echo ""
        echo "❌ BLOCKED - Tests FAILED"
        exit
      else
        echo "✅ PASSED - Unit tests passed."
      fi
    else
      echo "✅ PASSED - No adapter for tests, assuming none to run."
    fi
  else
    echo "✅ PASSED - No specific adapter, no tests to run."
  fi
  
  # Next, run coverage check
  echo "Running coverage check..."

  if [ "${PROJECT_LANG}" != "unknown" ] && [ -f "$ADAPTER_DIR/adapters/${PROJECT_LANG}.sh" ]; then
    if source "$ADAPTER_DIR/adapters/${PROJECT_LANG}.sh" 2>/dev/null; then
      case "$PROJECT_LANG" in
        "typescript")
          if [ -f "package.json" ] && grep -q '"test:coverage"' package.json 2>/dev/null; then
            echo "Running TypeScript coverage with minimum 80% requirement..."
            npx vitest run --coverage 2>&1
            COV_EXIT=$?
            if [ "$COV_EXIT" -ne 0 ]; then
              echo ""
              echo "❌ BLOCKED - Coverage check FAILED (exit code: $COV_EXIT)"
              echo "Coverage must meet the thresholds defined in vitest.config.ts"
              exit 1
            fi
          else
            echo "No 'test:coverage' script in package.json, running coverage via adapter..."
            run_coverage_output=$(run_coverage 2>&1)
            COV_EXIT=$?
            echo "$run_coverage_output" | head -30
          fi
          ;;
        "python")
          if command -v pytest &> /dev/null && command -v coverage &> /dev/null; then
            pytest --cov=. --cov-fail-under=80 --tb=short
            COV_EXIT=$?
          else
            echo "pytest/coverage not available, running coverage via adapter..."
            run_coverage_output=$(run_coverage 2>&1)
            COV_EXIT=$?
            echo "$run_coverage_output" | head -30
          fi
          ;;
        "go")
          if command -v go &> /dev/null; then
            go test -coverprofile=coverage.out ./... 2>/dev/null
            TOTAL_COVERAGE=$(go tool cover -func=coverage.out 2>/dev/null | grep "^total:" | awk '{print substr($3, 1, length($3)-1)}')
            if [ -n "$TOTAL_COVERAGE" ] && (( $(echo "$TOTAL_COVERAGE < 80" | bc -l 2>/dev/null || echo "0") )); then
              echo "❌ BLOCKED - Go coverage $TOTAL_COVERAGE% below 80% threshold"
              exit 1
            fi
            echo "Go coverage: $TOTAL_COVERAGE%"
            COV_EXIT=0
          fi
          ;;
        "shell")
          shell_cov_output=$(run_coverage 2>&1)
          COV_EXIT=$?
          echo "$shell_cov_output" | head -10
          echo "ℹ️  Shell coverage not typically measured"
          ;;
        *)
          default_cov_output=$(run_coverage 2>&1)
          COV_EXIT=$?
          echo "$default_cov_output" | head -30
          ;;
      esac
    else
      # Adapter source failed — warn and let Stage 2 attempt file-based enforcement
      echo "⚠️  Could not source ${PROJECT_LANG} adapter, will check coverage files directly..."
      COV_EXIT=0
    fi
  else
    # No adapter available — warn and let Stage 2 attempt file-based enforcement
    echo "⚠️  No adapter for ${PROJECT_LANG}, will check coverage files directly..."
    COV_EXIT=0
  fi

  # ============================================================================
  # Stage 2: UNCONDITIONAL coverage percentage enforcement
  # Always attempt to parse coverage from available sources. If percentage
  # can be determined and is < 80% → BLOCK. If no data found → warn.
  # ============================================================================
  COVERAGE_ENFORCED=false

  case "$PROJECT_LANG" in
    "typescript")
      COVERAGE_ENFORCED=true
      if [ -f "coverage/coverage-summary.json" ]; then
        COVERAGE_PERCENT=$(node -e "
          try {
            const fs = require('fs');
            const data = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
            console.log(Math.round(data.total.lines.pct));
          } catch(e) { console.log('parse_error'); }
        " 2>/dev/null)
        if [ "$COVERAGE_PERCENT" != "parse_error" ] && [ -n "$COVERAGE_PERCENT" ]; then
          if [ "$COVERAGE_PERCENT" -lt 80 ]; then
            echo "❌ BLOCKED - TypeScript coverage ${COVERAGE_PERCENT}% below 80% threshold"
            exit 1
          fi
          echo "TypeScript coverage: ${COVERAGE_PERCENT}% ✅ (≥ 80%)"
        else
          echo "⚠️  Could not parse TypeScript coverage from coverage/coverage-summary.json"
        fi
      else
        echo "⚠️  coverage/coverage-summary.json not found. If vitest --coverage was used, check vitest.config.ts coverageDirectory."
      fi
      ;;
    "python")
      COVERAGE_ENFORCED=true
      if command -v coverage &> /dev/null; then
        COVERAGE_PERCENT=""
        if [ -f ".coverage" ]; then
          COVERAGE_PERCENT=$(coverage report --format=total 2>/dev/null | grep -o '[0-9]*%' | head -1 | tr -d '%') || true
        fi
        if [ -z "$COVERAGE_PERCENT" ] && [ -f "coverage/.coverage" ]; then
          COVERAGE_PERCENT=$(coverage report --format=total -i coverage 2>/dev/null | grep -o '[0-9]*%' | head -1 | tr -d '%') || true
        fi
        if [ -n "$COVERAGE_PERCENT" ]; then
          if [ "$COVERAGE_PERCENT" -lt 80 ]; then
            echo "❌ BLOCKED - Python coverage ${COVERAGE_PERCENT}% below 80% threshold"
            exit 1
          fi
          echo "Python coverage: ${COVERAGE_PERCENT}% ✅ (≥ 80%)"
        else
          echo "⚠️  Could not determine Python coverage percentage. Ensure pytest-cov or coverage.py data exists."
        fi
      else
        echo "⚠️  coverage.py not available, cannot enforce Python coverage threshold."
      fi
      ;;
    "go")
      # Go enforcement already handled inline in Stage 1 (lines 933-942)
      ;;
    "shell")
      # Shell coverage not typically measured
      ;;
    "dart"|"flutter")
      COVERAGE_ENFORCED=true
      if [ -f "coverage/lcov.info" ]; then
        COVERAGE_PERCENT=$(parse_lcov_coverage "coverage/lcov.info" 2>/dev/null) || COVERAGE_PERCENT="0"
        if [ "$COVERAGE_PERCENT" != "0" ] && [ -n "$COVERAGE_PERCENT" ]; then
          if [ "$COVERAGE_PERCENT" -lt 80 ]; then
            echo "❌ BLOCKED - Flutter/Dart coverage ${COVERAGE_PERCENT}% below 80% threshold"
            exit 1
          fi
          echo "Flutter/Dart coverage: ${COVERAGE_PERCENT}% ✅ (≥ 80%)"
        else
          echo "⚠️  Could not determine Flutter/Dart coverage percentage from lcov.info."
        fi
      else
        echo "⚠️  coverage/lcov.info not found. Ensure dart test --coverage was run."
      fi
      ;;
    *)
      # Default: attempt to parse coverage from common formats regardless of language
      COVERAGE_ENFORCED=true
      COVERAGE_PERCENT=""
      if [ -f "coverage/coverage-summary.json" ]; then
        COVERAGE_PERCENT=$(node -e "
          try {
            const fs = require('fs');
            const data = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
            console.log(Math.round(data.total.lines.pct));
          } catch(e) { console.log('parse_error'); }
        " 2>/dev/null) || COVERAGE_PERCENT=""
      elif [ -f "coverage/lcov.info" ]; then
        if command -v parse_lcov_coverage &> /dev/null; then
          COVERAGE_PERCENT=$(parse_lcov_coverage "coverage/lcov.info" 2>/dev/null) || COVERAGE_PERCENT=""
        else
          COVERAGE_PERCENT=$(grep -oP 'SF:.*' coverage/lcov.info 2>/dev/null | wc -l || echo "0")
          # Simple fallback: check lcov for coverage percentage
          COVERAGE_PERCENT=$(grep -oP 'coverage: \K[0-9]+%' coverage/lcov.info 2>/dev/null | head -1 | tr -d '%') || COVERAGE_PERCENT=""
        fi
      fi
      if [ -n "$COVERAGE_PERCENT" ] && [ "$COVERAGE_PERCENT" != "parse_error" ] && [ "$COVERAGE_PERCENT" -gt 0 ]; then
        if [ "$COVERAGE_PERCENT" -lt 80 ]; then
          echo "❌ BLOCKED - ${PROJECT_LANG} coverage ${COVERAGE_PERCENT}% below 80% threshold"
          exit 1
        fi
        echo "${PROJECT_LANG} coverage: ${COVERAGE_PERCENT}% ✅ (≥ 80%)"
      else
        echo "⚠️  Could not determine ${PROJECT_LANG} coverage percentage. No standard coverage report files found."
      fi
      ;;
  esac

  if [ "$COV_EXIT" -ne 0 ]; then
    echo ""
    echo "❌ BLOCKED - Coverage check FAILED"
    exit 1
  fi
  if [ "$COVERAGE_ENFORCED" = false ]; then
    echo "ℹ️  Coverage enforcement not applicable for ${PROJECT_LANG}"
  fi
  echo "✅ PASSED - Coverage check completed."
fi
GATE_5_STATUS="PASS"

# ============================================================================
# GATE 6: Architecture & Tech Debt (Combines Old Gate 8 - Boy Scout and Gate 9 - Architecture)
# ============================================================================
2>&1 echo ""
2>&1 echo "→ Gate 6: Architecture & tech debt..."

# First Part: Architecture Validation (previously Gate 9)
2>&1 echo "   └─ Architecture validation:"

if [ "$PROJECT_LANG" = "documentation-only" ]; then
  echo "     ✅ Skipped (documentation project)."

elif [ "$PROJECT_LANG" = "powershell" ]; then
  echo "     ℹ️  No PowerShell architecture tooling available"
  echo "     ✅ Architecture validation (SKIP, no tool for PowerShell)"

else
  # Check if architecture config exists
  if [ -f "architecture.yaml" ] || [ -f ".architecturerc" ] || [ -f ".archlint.yaml" ]; then
    # Different architecture tools per language
    case "$PROJECT_LANG" in
      "typescript")
        # Try local npx install first (devDependencies), fall back to global
        if npx --no-install @archlinter/cli --version >/dev/null 2>&1; then
          ARCHLINT_CMD="npx --no-install @archlinter/cli"
        elif command -v archlint >/dev/null 2>&1; then
          ARCHLINT_CMD="archlint"
        elif npx @archlinter/cli --version >/dev/null 2>&1; then
          ARCHLINT_CMD="npx @archlinter/cli"
        else
          echo "     ❌ BLOCKED - archlint not installed"
          echo "     Install with: npm install --save-dev @archlinter/cli"
          exit 1
        fi
        echo "     Running archlint for TypeScript..."
        ARCHLINT_OUTPUT=$($ARCHLINT_CMD scan . -f table --quiet 2>&1)
        ARCHLINT_EXIT=$?
        echo "$ARCHLINT_OUTPUT" | tail -30
        if [ "$ARCHLINT_EXIT" -ne 0 ]; then
          echo ""
          echo "❌ BLOCKED - Architecture violations detected"
          echo "Fix the architecture violations above before committing."
          exit 1
        fi
        echo "     ✅ TypeScript architecture validation completed."
        ;;
      "python")
        if [ -f ".import-linter.yml" ] || [ -f "import_linter_config.yml" ]; then
          if require_tool "lint-imports" "Gate 6" "pip install import-linter"; then
            echo "     Running import-linter for Python..."
            lint-imports 2>&1 | head -20
            echo "     ✅ Python architecture validation completed."
          else
            echo "     ❌ BLOCKED - import-linter not installed"
            echo "     Install with: pip install import-linter"
            exit
          fi
        else
          echo "     ℹ️  No .import-linter.yml found - skipping Python architecture"
          echo "     ✅ Python architecture validation (SKIP, no config)"
        fi
        ;;
      "go")
        if [ -f "arch-go.yaml" ] || [ -f "arch-go.yml" ]; then
          if require_tool "arch-go" "Gate 6" "go install github.com/arch-go/arch-go@latest"; then
            echo "     Running arch-go for Go..."
            arch-go check 2>&1 | head -20
            echo "     ✅ Go architecture validation completed."
          else
            echo "     ❌ BLOCKED - arch-go not installed"
            echo "     Install with: go install github.com/arch-go/arch-go@latest"
            exit
          fi
        else
          echo "     ℹ️  No arch-go.yaml found - skipping Go architecture"
          echo "     ✅ Go architecture validation (SKIP, no config)"
        fi
        ;;
      "java")
        if [ -f "src/test/java/architecture" ] || [ -d "src/test/java/architecture" ]; then
          echo "     Running Java architecture tests..."
          if [ -f "pom.xml" ]; then
            mvn test -Dtest=architecture.* 2>&1 | head -20 || mvn test -Dtest=**Architecture** 2>&1 | head -20 || echo "⚠️  Java architecture tests completed"
          elif [ -f "build.gradle" ]; then
            if [ -f "./gradlew" ]; then
              ./gradlew test --tests "*Architecture*" 2>&1 | head -20 || echo "⚠️  Java architecture tests completed"
            fi
          fi
          echo "     ✅ Java architecture validation completed."
        else
          echo "     ℹ️  No architecture test files found - skipping"
          echo "     ✅ Architecture validation (SKIP, no tests)"
        fi
        ;;
      *)
        echo "     ℹ️  Architecture validation not configured for $PROJECT_LANG"
        echo "     ✅ Architecture validation (SKIP, not configured)"
        ;;
    esac
  else
    # Architecture config is REQUIRED — BLOCK if missing
    if [ -f ".architecture-skip" ]; then
      echo "     ⚠️  Architecture config missing but .architecture-skip present — allowed to skip"
      echo "     ✅ Architecture validation (SKIP, .architecture-skip exemption)"
    else
      echo ""
      echo "❌ ARCHITECTURE CONFIG MISSING - COMMIT BLOCKED"
      echo "   Required configuration file 'architecture.yaml' is NOT found."
      echo "   Architecture Quality Gate requires explicit architecture constraints."
      echo ""
      echo "   Create architecture.yaml with:"
      echo "     layers:"
      echo "       - name: api"
      echo "         paths: [\"src/api/**\"]"
      echo "       - name: domain"
      echo "         paths: [\"src/domain/**\"]"
      echo "         allowed_imports: [domain]"
      echo "       - name: infrastructure"
      echo "         paths: [\"src/infrastructure/**\"]"
      echo "         allowed_imports: [domain, infrastructure]"
      echo ""
      echo "   After creating architecture.yaml, retry the commit."
      echo "   (To skip with warning, create .architecture-skip file)"
      exit
    fi
  fi
fi

# Second Part: Boy Scout Rule (previously Gate 8) - Unified Enforcement
2>&1 echo "   └─ Boy Scout Rule enforcement:"

if [ "$PROJECT_LANG" = "documentation-only" ]; then
  echo "     ✅ Skipped (documentation project)."
  
else
  # Check if principles directory exists for Boy Scout
  if [ -f "src/principles/boy-scout.ts" ]; then
    echo "     Checking Boy Scout Rule compliance..."
    
    # Separate new files and modified files
    NEW_FILES=$(git diff --cached --name-only --diff-filter=A | tr '\n' ' ')
    MODIFIED_FILES=$(git diff --cached --name-only --diff-filter=M | tr '\n' ' ') 
    
    if [ -z "$NEW_FILES" ] && [ -z "$MODIFIED_FILES" ]; then
      echo "     ✅ No new or modified files to check."
    else
      # Run Boy Scout Rule enforcement
      if command -v npx &> /dev/null; then
        # Skip if no files to check
        if [ -z "$(echo "$NEW_FILES" | tr -d ' ')" ] && [ -z "$(echo "$MODIFIED_FILES" | tr -d ' ')" ]; then
          echo "     ✅ No new or modified source files for Boy Scout check."
        else
          BOY_SCOUT_OUTPUT=$(npx tsx src/principles/boy-scout.ts \
            --new-files "$(echo "$NEW_FILES" | tr ' ' ',')" \
            --modified-files "$(echo "$MODIFIED_FILES" | tr ' ' ',')" \
            --baseline ".warnings-baseline.json" 2>&1)
        
        BOY_SCOUT_EXIT=$?
        
        if [ "$BOY_SCOUT_EXIT" -ne 0 ]; then
          echo "$BOY_SCOUT_OUTPUT"
          echo ""
          echo "❌ BLOCKED - Boy Scout Rule violation"
          echo "Requirements:"
          echo "  - NEW files: must have zero warnings"
          echo "  - MODIFIED files: cannot increase warnings from baseline"
          echo "  - Files with ≤5 warnings: must clear to zero"
          exit
        fi
        
        # Check output for violations
        VIOLATION_COUNT=$(echo "$BOY_SCOUT_OUTPUT" | grep -c '"enforcement": "BLOCK"' 2>/dev/null || true)
        VIOLATION_COUNT=${VIOLATION_COUNT:-0}
        if [ "$VIOLATION_COUNT" -gt 0 ]; then
          echo "$BOY_SCOUT_OUTPUT"
          echo ""
          echo "❌ BLOCKED - Boy Scout Rule violations detected ($VIOLATION_COUNT)"
          exit
        fi
        
        echo "     ✅ PASSED - Boy Scout Rule compliance."
        fi
      else
        echo "     ℹ️  npx not available - skipping Boy Scout Rule"
        echo "     ✅ Boy Scout Rule (SKIP, Node.js not available)"
      fi
    fi
  else
    echo "     ℹ️  Boy scout rule not available in project - skipping"
    echo "     ✅ Boy Scout Rule (SKIP, not available in project)"
  fi
fi
GATE_6_STATUS="PASS"

# ============================================================================

# ============================================================================
# GATE 7: IaC Security Scanning (Terraform, Kubernetes, Docker)
# Detects security issues in Infrastructure as Code files
# Tools: checkov (recommended), hadolint, kube-score, tflint
# ============================================================================
2>&1 echo ""
2>&1 echo "→ Gate 7: IaC Security Scanning (Terraform, Kubernetes, Docker)..."

# Check if any IaC files are changed
IAC_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -E "\.(tf|yaml|yml)$|Dockerfile" || true)
if [ -z "$IAC_FILES" ]; then
  echo "✅ PASSED - No IaC files detected in changes."
  GATE_7_STATUS="PASS"
else
  # Run IaC adapter
  if [ -f "githooks/adapters/iac.sh" ]; then
    # shellcheck source=githooks/adapters/iac.sh
    source "githooks/adapters/iac.sh"
    
    # Run static analysis for IaC files
    IAC_OUTPUT=$(run_static_analysis "$IAC_FILES" 2>&1)
    IAC_EXIT=$?
    
    echo "$IAC_OUTPUT"
    
    if [ $IAC_EXIT -eq 0 ]; then
      echo "✅ PASSED - IaC security scan."
      GATE_7_STATUS="PASS"
    else
      echo ""
      echo "❌ BLOCKED - IaC security issues detected"
      echo "Fix the security issues above before committing."
      echo "Tip: Install checkov for comprehensive IaC scanning: pip install checkov"
      GATE_7_STATUS="FAIL"
      exit
    fi
  else
    echo "ℹ️  SKIP - IaC adapter not found"
    echo "✅ PASSED - IaC Security (SKIP)"
    GATE_7_STATUS="SKIP"
  fi
fi


# GATE 8: Secret Scanning (gitleaks)
# Detects secrets (API keys, passwords, tokens) in staged files
# Tool: gitleaks -- https://github.com/gitleaks/gitleaks
# ============================================================================

2>&1 echo ""
2>&1 echo "→ Gate 8: Secret scanning (gitleaks)..."

# Gitleaks availability check
GITLEAKS_CMD=""
if command -v gitleaks >/dev/null 2>&1; then
  GITLEAKS_CMD="gitleaks"
elif [ -f "$HOME/.local/bin/gitleaks" ]; then
  GIBLEAKS_CMD="$HOME/.local/bin/gitleaks"
fi

if [ -n "$GITLEAKS_CMD" ]; then
  GITLEAKS_CONFIG=""
  if [ -f ".gitleaks.toml" ]; then
    GITLEAKS_CONFIG="--config=.gitleaks.toml"
  fi

  # Run gitleaks on staged changes only (pre-commit mode for speed)
  GITLEAKS_OUTPUT=$($GITLEAKS_CMD git --pre-commit --redact --no-banner $GITLEAKS_CONFIG --report-format=json --report-path=/tmp/gitleaks-report.json 2>&1)
  GITLEAKS_EXIT=$?

  if [ "$GITLEAKS_EXIT" -eq 0 ]; then
    echo "     ✅ PASSED - No secrets detected."
    GATE_8_STATUS="PASS"
  elif [ "$GITLEAKS_EXIT" -eq 1 ]; then
    # Secrets found — output details
    echo "$GITLEAKS_OUTPUT"
    echo ""
    echo "❌ BLOCKED - Secrets detected in staged files."
    echo ""
    echo "Remediation options:"
    echo "  1. Remove the secret and use environment variables instead"
    echo "  2. Add a false positive to .gitleaks.toml allowlist"
    echo "  3. Use git secret or vault for sensitive data"
    echo ""
    echo "See: https://github.com/gitleaks/gitleaks"
    exit
  else
    echo "     ⚠️  gitleaks exited with code $GITLEAKS_EXIT - skipping gate"
    echo "     ✅ Secret Scanning (SKIP, gitleaks error)"
    GATE_8_STATUS="SKIP"
  fi
else
  echo "     ℹ️  gitleaks not installed — secret scanning unavailable"
  echo "     Install: brew install gitleaks (macOS) | scripts/install-gitleaks.sh (Linux)"
  echo "     ✅ Secret Scanning (SKIP, gitleaks not installed)"
  GATE_8_STATUS="SKIP"
fi

# Switch back to original directory if we were in a subdirectory
if [ -n "$ORIGINAL_DIR" ]; then
  cd "$ORIGINAL_DIR" 
fi

# ============================================================================
# GATE 9: Semgrep SAST Security Scan
# Detects security vulnerabilities (SQL injection, XSS, etc.) in staged files
# Tool: semgrep -- https://semgrep.dev
# ============================================================================

2>&1 echo ""
2>&1 echo "→ Gate 9: Semgrep SAST Security Scan..."

GATE_9_STATUS="PASS"

# Semgrep availability check
SEMGREP_CMD=""
if command -v semgrep >/dev/null 2>&1; then
  SEMGREP_CMD="semgrep"
elif [ -f "$HOME/.local/bin/semgrep" ]; then
  SEMGREP_CMD="$HOME/.local/bin/semgrep"
fi

if [ -z "$SEMGREP_CMD" ]; then
  echo "     ℹ️  semgrep not installed — SAST scanning unavailable"
  echo "     Install: brew install semgrep | pip install semgrep"
  echo "     Pre-cache rules: semgrep --config=p/security-audit"
  echo "     ✅ Semgrep SAST (SKIP, semgrep not installed)"
  GATE_9_STATUS="SKIP"
else
  # Get staged files filtered to Semgrep-supported languages
  SEMGREP_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -E '\.(ts|tsx|js|jsx|py|go|java|c|cpp|cs|rb|php|scala|swift)$' || true)

  if [ -z "$SEMGREP_FILES" ]; then
    echo "     ✅ PASSED - No supported language files in staged changes."
    GATE_9_STATUS="PASS"
  else
    # Run semgrep with JSON output
    # --config=p/security-audit: explicit security ruleset
    # --json: machine-readable output
    # --disable-version-check: skip network call
    SEMGREP_OUTPUT=$($SEMGREP_CMD scan --config=p/security-audit --json --disable-version-check $SEMGREP_FILES 2>&1)
    SEMGREP_EXIT=$?

    if [ "$SEMGREP_EXIT" -eq 0 ]; then
      echo "     ✅ PASSED - No security vulnerabilities found."
      GATE_9_STATUS="PASS"
    elif [ "$SEMGREP_EXIT" -eq 1 ]; then
      # Findings detected - parse JSON to categorize
      CRITICAL_HIGH=$(echo "$SEMGREP_OUTPUT" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    results = data.get('results', [])
    count = 0
    for r in results:
        extra = r.get('extra', {})
        severity = extra.get('severity', '').upper()
        if severity in ('CRITICAL', 'HIGH'):
            count += 1
    print(count)
except:
    print('0')
" 2>/dev/null || echo "0")

      MEDIUM_LOW=$(echo "$SEMGREP_OUTPUT" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    results = data.get('results', [])
    count = 0
    for r in results:
        extra = r.get('extra', {})
        severity = extra.get('severity', '').upper()
        if severity in ('MEDIUM', 'LOW'):
            count += 1
    print(count)
except:
    print('0')
" 2>/dev/null || echo "0")

      # Extract top finding details
      FINDING_DETAILS=$(echo "$SEMGREP_OUTPUT" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    results = data.get('results', [])
    for r in results[:5]:  # Show top 5
        extra = r.get('extra', {})
        severity = extra.get('severity', 'UNKNOWN').upper()
        rule_id = r.get('check_id', 'unknown')
        path = r.get('path', 'unknown')
        start_line = r.get('start', {}).get('line', '?')
        message = extra.get('message', '')[:80]
        print(f'  [{severity}] {rule_id}')
        print(f'  {path}:{start_line} → {message}')
        print()
except:
    print('  (Failed to parse semgrep output)')
" 2>/dev/null || echo "  (Failed to parse semgrep output)")

      if [ "$CRITICAL_HIGH" -gt 0 ]; then
        echo ""
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        echo "   GATE 9: Semgrep Security Gate"
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        echo "  CRITICAL/HIGH: ${CRITICAL_HIGH}  ❌ BLOCKED"
        echo "  MEDIUM/LOW:    ${MEDIUM_LOW}  ⚠️  warning"
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        echo "  ❌ BLOCKED — Critical/High vulnerability found"
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        echo "$FINDING_DETAILS"
        echo "  Run 'semgrep scan --config=p/security-audit' to review all findings."
        GATE_9_STATUS="FAIL"
        exit
      else
        echo ""
        echo "     ✅ PASSED - No critical/high vulnerabilities"
        if [ "$MEDIUM_LOW" -gt 0 ]; then
          echo "     ⚠️  ${MEDIUM_LOW} medium/low findings (warnings only)"
          echo "$FINDING_DETAILS"
        fi
        GATE_9_STATUS="PASS"
      fi
    else
      # semgrep runtime error (timeout, config error, etc.)
      echo "     ⚠️  semgrep exited with code ${SEMGREP_EXIT} — skipping gate"
      echo "     ✅ Semgrep SAST (SKIP, semgrep error)"
      GATE_9_STATUS="SKIP"
    fi
  fi
fi

# ============================================================================
# QUALITY REPORT GENERATION
# ============================================================================

generate_quality_report() {
  local HISTORY_FILE=".quality-history.jsonl"
  local COMMIT_HASH
  local TIMESTAMP
  local BRANCH
  local PASSED_COUNT=0
  local TOTAL_GATES=9

  COMMIT_HASH=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
  BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
  TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

  for gate in 1 2 3 4 5 6 7 8 9; do
    local status_var="GATE_${gate}_STATUS"
    if [ "${!status_var}" = "PASS" ] || [ "${!status_var}" = "SKIP" ]; then
      PASSED_COUNT=$((PASSED_COUNT + 1))
    fi
  done

  local SCORE=0
  if command -v bc >/dev/null 2>&1; then
    SCORE=$(echo "scale=1; ($PASSED_COUNT / $TOTAL_GATES) * 10" | bc)
  else
    SCORE=$(awk "BEGIN {printf \"%.1f\", ($PASSED_COUNT / $TOTAL_GATES) * 10}")
  fi

  local BS_PASSED=0
  local BS_BLOCKED=0
  if [ -n "$BOY_SCOUT_OUTPUT" ]; then
    BS_PASSED=$(echo "$BOY_SCOUT_OUTPUT" | grep -o '"passedFiles": [0-9]*' | grep -o '[0-9]*' || echo "0")
    BS_BLOCKED=$(echo "$BOY_SCOUT_OUTPUT" | grep -o '"blockedFiles": [0-9]*' | grep -o '[0-9]*' || echo "0")
  fi

  local COV_PCT="${COVERAGE_PERCENT:-N/A}"

  # ── Build failed-tests list from TESTS_OUTPUT (Gate 5) ──────────────────────────────
  local FAILED_TESTS_JSON="[]"
  if [ -n "$TESTS_OUTPUT" ] && echo "$TESTS_OUTPUT" | grep -qi "fail\|error\|FAILED"; then
    # Extract failure lines: "FAIL src/foo.test.ts" or "  ✗ test name"
    local FAIL_LINES
    FAIL_LINES=$(echo "$TESTS_OUTPUT" | grep -E "^\s*(FAIL|✗|failed|AssertionError)" | head -10 | \
      sed 's/"/\\"/g' | awk '{ printf "%s%s%s", sep, "\"", $0; sep="," }')
    if [ -n "$FAIL_LINES" ]; then
      FAILED_TESTS_JSON="[$FAIL_LINES]"
    fi
  fi

  # ── Branch-level quality status file ─────────────────────────────────────────────
  local STATUS_DIR=".xp-gate/quality-status"
  local REPORT_FILE="${STATUS_DIR}/${BRANCH}.json"
  mkdir -p "$STATUS_DIR"

  cat > "$REPORT_FILE" << ENDJSON
{
  "reportVersion": "1.1",
  "generatedAt": "$TIMESTAMP",
  "branch": "$BRANCH",
  "commit": "$COMMIT_HASH",
  "language": "${PROJECT_LANG:-unknown}",
  "overall": {
    "gatesPassed": $PASSED_COUNT,
    "gatesTotal": $TOTAL_GATES,
    "score": $SCORE,
    "verdict": "$([ "$PASSED_COUNT" -eq "$TOTAL_GATES" ] && echo "PASS" || echo "PARTIAL")"
  },
  "gates": {
    "gate1_static_analysis": {
      "name": "Code Quality (Static + Lint + Shell)",
      "status": "${GATE_1_STATUS:-PASS}",
      "tool": "${GATE_1_TOOL:-auto}"
    },
    "gate2_dup_code": {
      "name": "Duplicate Code",
      "status": "${GATE_2_STATUS:-PASS}",
      "metric": "similarity <= 5%"
    },
    "gate3_complexity": {
      "name": "Cyclomatic Complexity",
      "status": "${GATE_3_STATUS:-PASS}",
      "threshold": "${CCN_THRESHOLD:-5}",
      "blockThreshold": "${CCN_THRESHOLD:-5}",
      "warnings": ${CC_WARNINGS:-0}
    },
    "gate4_principles": {
      "name": "Clean Code + SOLID",
      "status": "${GATE_4_STATUS:-PASS}",
      "warnings": ${WARNING_COUNT:-0}
    },
    "gate5_tests": {
      "name": "Tests + Coverage",
      "status": "${GATE_5_STATUS:-PASS}",
      "thresholds": { "lines": 80, "functions": 80, "branches": 70, "statements": 80 },
      "actual": { "coverage": "${COV_PCT}" },
      "failedTests": $FAILED_TESTS_JSON
    },
    "gate6_arch_boyscout": {
      "name": "Architecture + Boy Scout Rule",
      "status": "${GATE_6_STATUS:-PASS}",
      "boyScoutPassed": $BS_PASSED,
      "boyScoutBlocked": $BS_BLOCKED
    },
    "gate7_iac_security": {
      "name": "IaC Security Scanning",
      "status": "${GATE_7_STATUS:-PASS}",
      "tools": "checkov, hadolint, kube-score, tflint"
    },
    "gate8_secret_scanning": {
      "name": "Secret Scanning",
      "status": "${GATE_8_STATUS:-PASS}",
      "tool": "gitleaks"
    },
    "gate9_sast": {
      "name": "SAST Security Scan",
      "status": "${GATE_9_STATUS:-PASS}",
      "tool": "semgrep"
    }
  }
}
ENDJSON

  # ── History append (unchanged — append-only for trend) ────────────────────────────
  local GATES_JSON="{"
  GATES_JSON="${GATES_JSON}\"gate1\":{\"status\":\"${GATE_1_STATUS:-PASS}\",\"name\":\"Code Quality\"},"
  GATES_JSON="${GATES_JSON}\"gate2\":{\"status\":\"${GATE_2_STATUS:-PASS}\",\"name\":\"Duplicate Code\"},"
  GATES_JSON="${GATES_JSON}\"gate3\":{\"status\":\"${GATE_3_STATUS:-PASS}\",\"name\":\"Complexity\",\"warnings\":${CC_WARNINGS:-0}},"
  GATES_JSON="${GATES_JSON}\"gate4\":{\"status\":\"${GATE_4_STATUS:-PASS}\",\"name\":\"Principles\",\"warnings\":${WARNING_COUNT:-0}},"
  GATES_JSON="${GATES_JSON}\"gate5\":{\"status\":\"${GATE_5_STATUS:-PASS}\",\"name\":\"Tests+Coverage\",\"coverage\":\"${COV_PCT}\"},"
  GATES_JSON="${GATES_JSON}\"gate6\":{\"status\":\"${GATE_6_STATUS:-PASS}\",\"name\":\"Architecture+BoyScout\",\"bsBlocked\":${BS_BLOCKED}},"
  GATES_JSON="${GATES_JSON}\"gate7\":{\"status\":\"${GATE_7_STATUS:-PASS}\",\"name\":\"IaC Security\"},"
  GATES_JSON="${GATES_JSON}\"gate8\":{\"status\":\"${GATE_8_STATUS:-PASS}\",\"name\":\"Secret Scanning\"},"
  GATES_JSON="${GATES_JSON}\"gate9\":{\"status\":\"${GATE_9_STATUS:-PASS}\",\"name\":\"SAST Security\"}}"
  GATES_JSON="${GATES_JSON}}"

  echo "{\"timestamp\":\"$TIMESTAMP\",\"commit\":\"$COMMIT_HASH\",\"branch\":\"$BRANCH\",\"score\":$SCORE,\"passed\":$PASSED_COUNT,\"total\":$TOTAL_GATES,\"gates\":$GATES_JSON,\"coverage\":\"$COV_PCT\",\"complexityWarnings\":${CC_WARNINGS:-0},\"principleWarnings\":${WARNING_COUNT:-0},\"boyScoutBlocked\":${BS_BLOCKED}}" >> "$HISTORY_FILE"

  # ── Console output ────────────────────────────────────────────────────────
  echo ""
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  echo "  📊 Quality Report — $TIMESTAMP"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  echo ""
  printf "  %-45s %s\n" "Gate 1: Code Quality" "${GATE_1_STATUS:-PASS}"
  printf "  %-45s %s\n" "Gate 2: Duplicate Code" "${GATE_2_STATUS:-PASS}"
  printf "  %-45s %s (warnings: ${CC_WARNINGS:-0})\n" "Gate 3: Complexity" "${GATE_3_STATUS:-PASS}"
  printf "  %-45s %s (warnings: ${WARNING_COUNT:-0})\n" "Gate 4: Principles" "${GATE_4_STATUS:-PASS}"
  printf "  %-45s %s (coverage: ${COV_PCT}%%)\n" "Gate 5: Tests + Coverage" "${GATE_5_STATUS:-PASS}"
  printf "  %-45s %s\n" "Gate 6: Architecture + Boy Scout" "${GATE_6_STATUS:-PASS}"
  printf "  %-45s %s\n" "Gate 7: IaC Security" "${GATE_7_STATUS:-PASS}"
  printf "  %-45s %s\n" "Gate 8: Secret Scanning" "${GATE_8_STATUS:-PASS}"
  printf "  %-45s %s\n" "Gate 9: SAST Security" "${GATE_9_STATUS:-PASS}"
  echo ""
  echo "  Overall Score: $SCORE/10 | $PASSED_COUNT/$TOTAL_GATES gates passed"
  echo "  Branch status: $REPORT_FILE"
  echo "  History saved: $HISTORY_FILE"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  echo ""
}

generate_quality_report

exit