#!/bin/sh
# Palimpsest License - Pre-commit Git Hook
# SPDX-License-Identifier: Palimpsest-0.4 OR MIT
# Version: 0.4.0
#
# This hook validates commits before they are created to ensure:
# - SPDX license headers are present
# - Code is properly formatted
# - No secrets are committed
# - Spell checking passes (British English)
# - License audit passes

set -e

# Colour codes for output (British spelling in comments)
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Colour

# Helper functions
print_header() {
    echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
    echo "${BLUE}  $1${NC}"
    echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}

print_success() {
    echo "${GREEN}✓${NC} $1"
}

print_error() {
    echo "${RED}✗${NC} $1"
}

print_warning() {
    echo "${YELLOW}⚠${NC} $1"
}

print_info() {
    echo "${BLUE}ℹ${NC} $1"
}

# Check if running in CI (skip interactive checks)
if [ -n "$CI" ]; then
    print_info "Running in CI mode, skipping interactive checks"
fi

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

if [ -z "$STAGED_FILES" ]; then
    print_warning "No staged files to check"
    exit 0
fi

print_header "Pre-commit Validation"

# ============================================================================
# CHECK 1: SPDX License Headers
# ============================================================================

print_info "Checking SPDX license headers..."

MISSING_SPDX=0

# Check Haskell files
for file in $STAGED_FILES; do
    case "$file" in
        *.hs)
            if ! grep -q "SPDX-License-Identifier:" "$file"; then
                print_error "Missing SPDX header: $file"
                MISSING_SPDX=1
            fi
            ;;
        *.res)
            if ! grep -q "SPDX-License-Identifier:" "$file"; then
                print_error "Missing SPDX header: $file"
                MISSING_SPDX=1
            fi
            ;;
        *.js)
            # Skip node_modules and generated files
            if echo "$file" | grep -qv "node_modules\|dist\|lib"; then
                if ! grep -q "SPDX-License-Identifier:" "$file"; then
                    print_warning "Missing SPDX header: $file (JavaScript)"
                fi
            fi
            ;;
        *.ncl)
            if ! grep -q "SPDX-License-Identifier:" "$file"; then
                print_error "Missing SPDX header: $file"
                MISSING_SPDX=1
            fi
            ;;
    esac
done

if [ $MISSING_SPDX -eq 0 ]; then
    print_success "SPDX headers validated"
else
    print_error "SPDX header validation failed"
    print_info "Add this header to your files:"
    echo "    -- SPDX-License-Identifier: Palimpsest-0.4 OR MIT"
    exit 1
fi

# ============================================================================
# CHECK 2: Format Check (Prettier)
# ============================================================================

print_info "Checking code formatting..."

FORMAT_ISSUES=0

for file in $STAGED_FILES; do
    case "$file" in
        *.md|*.json|*.yml|*.yaml)
            if command -v npx >/dev/null 2>&1; then
                if ! npx prettier --check "$file" >/dev/null 2>&1; then
                    print_error "Formatting issue: $file"
                    FORMAT_ISSUES=1
                fi
            else
                print_warning "Prettier not found, skipping format check"
                break
            fi
            ;;
    esac
done

if [ $FORMAT_ISSUES -eq 1 ]; then
    print_error "Format check failed"
    print_info "Run 'just format' or 'npm run format' to fix formatting issues"
    exit 1
else
    print_success "Format check passed"
fi

# ============================================================================
# CHECK 3: Spell Check (British English)
# ============================================================================

print_info "Running spell check (British English)..."

SPELL_ERRORS=0

for file in $STAGED_FILES; do
    case "$file" in
        *.md)
            if command -v cspell >/dev/null 2>&1; then
                if ! npx cspell --language-id en-GB "$file" >/dev/null 2>&1; then
                    print_warning "Potential spelling issues: $file"
                    # Don't fail on spelling errors, just warn
                fi
            else
                # Skip if cspell not installed
                :
            fi
            ;;
    esac
done

if [ $SPELL_ERRORS -eq 0 ]; then
    print_success "Spell check completed"
fi

# ============================================================================
# CHECK 4: Secret Scanning
# ============================================================================

print_info "Scanning for secrets and sensitive data..."

SECRETS_FOUND=0

# Patterns to detect secrets
SECRET_PATTERNS=(
    "api[_-]?key.*['\"][a-zA-Z0-9]{20,}"
    "secret[_-]?key.*['\"][a-zA-Z0-9]{20,}"
    "private[_-]?key.*['\"][a-zA-Z0-9]{20,}"
    "password.*['\"][a-zA-Z0-9]{8,}"
    "BEGIN.*PRIVATE KEY"
    "aws_access_key_id"
    "aws_secret_access_key"
)

for file in $STAGED_FILES; do
    # Skip binary files and known safe files
    case "$file" in
        *.png|*.jpg|*.jpeg|*.gif|*.pdf|*.ico|*.woff|*.woff2|*.ttf|*.eot)
            continue
            ;;
    esac

    for pattern in "${SECRET_PATTERNS[@]}"; do
        if grep -iE "$pattern" "$file" >/dev/null 2>&1; then
            print_error "Potential secret detected in: $file"
            print_warning "Pattern matched: $pattern"
            SECRETS_FOUND=1
        fi
    done
done

# Check for common sensitive files
SENSITIVE_FILES=".env .env.local .env.production credentials.json secrets.yml"

for file in $STAGED_FILES; do
    filename=$(basename "$file")
    for sensitive in $SENSITIVE_FILES; do
        if [ "$filename" = "$sensitive" ]; then
            print_error "Attempting to commit sensitive file: $file"
            SECRETS_FOUND=1
        fi
    done
done

if [ $SECRETS_FOUND -eq 1 ]; then
    print_error "Secret scanning failed"
    print_info "Remove secrets from your code or use git-crypt for encryption"
    exit 1
else
    print_success "No secrets detected"
fi

# ============================================================================
# CHECK 5: License Audit (for dependencies)
# ============================================================================

print_info "Checking for dependency changes..."

DEPENDENCY_CHANGES=0

for file in $STAGED_FILES; do
    case "$file" in
        package.json|package-lock.json|*.cabal|cabal.project|cabal.project.freeze)
            print_warning "Dependency file changed: $file"
            DEPENDENCY_CHANGES=1
            ;;
    esac
done

if [ $DEPENDENCY_CHANGES -eq 1 ]; then
    print_warning "Dependency files modified - remember to audit licenses"
    print_info "Run 'npm audit' or check dependency licenses"
fi

# ============================================================================
# CHECK 6: Markdown Lint
# ============================================================================

print_info "Linting markdown files..."

MARKDOWN_ISSUES=0

for file in $STAGED_FILES; do
    case "$file" in
        *.md)
            if command -v markdownlint >/dev/null 2>&1; then
                if ! markdownlint "$file" >/dev/null 2>&1; then
                    print_warning "Markdown linting issue: $file"
                    # Don't fail, just warn
                fi
            fi
            ;;
    esac
done

print_success "Markdown linting completed"

# ============================================================================
# CHECK 7: British English Consistency
# ============================================================================

print_info "Checking for British English consistency..."

AMERICAN_SPELLINGS_FOUND=0

# Common American spellings to detect
AMERICAN_WORDS="color,favor,honor,labor,neighbor,organization,recognize,analyze,license,defense,offense,practice,traveling"

for file in $STAGED_FILES; do
    case "$file" in
        *.md|*.txt)
            # Skip specific files that might contain American English examples
            if echo "$file" | grep -q "examples\|vignettes\|quotes"; then
                continue
            fi

            for word in $(echo "$AMERICAN_WORDS" | tr ',' ' '); do
                # Use word boundaries to avoid false positives
                if grep -iw "$word" "$file" >/dev/null 2>&1; then
                    print_warning "Potential American spelling in $file: '$word'"
                    print_info "Consider British spelling: colour, favour, honour, labour, neighbour, organisation, recognise, analyse, licence (noun), defence, offence, practise (verb), travelling"
                    # Don't fail, just warn
                fi
            done
            ;;
    esac
done

print_success "British English check completed"

# ============================================================================
# CHECK 8: Large Files
# ============================================================================

print_info "Checking for large files..."

LARGE_FILES=0
MAX_FILE_SIZE=1048576  # 1MB in bytes

for file in $STAGED_FILES; do
    if [ -f "$file" ]; then
        filesize=$(wc -c < "$file")
        if [ "$filesize" -gt "$MAX_FILE_SIZE" ]; then
            filesizeMB=$(echo "scale=2; $filesize / 1048576" | bc 2>/dev/null || echo "unknown")
            print_warning "Large file detected: $file (${filesizeMB}MB)"
            print_info "Consider using Git LFS for large files"
            LARGE_FILES=1
        fi
    fi
done

if [ $LARGE_FILES -eq 0 ]; then
    print_success "No large files detected"
fi

# ============================================================================
# SUMMARY
# ============================================================================

print_header "Pre-commit Validation Complete"
print_success "All checks passed! Proceeding with commit."

echo ""
print_info "Files to be committed: $(echo "$STAGED_FILES" | wc -l)"

exit 0
