#!/bin/sh
# Palimpsest License - Pre-push Git Hook
# SPDX-License-Identifier: Palimpsest-0.4 OR MIT
# Version: 0.4.0
#
# This hook runs comprehensive checks before pushing to remote:
# - Full test suite execution
# - Security vulnerability scan
# - Build verification
# - RSR compliance check
# - License audit

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 ""
    echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
    echo "${BLUE}  $1${NC}"
    echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
    echo ""
}

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"
fi

# Get remote name and URL
remote="$1"
url="$2"

print_header "Pre-push Validation"
print_info "Remote: $remote"
print_info "URL: $url"

# Read standard input for refs being pushed
# Format: <local ref> <local sha> <remote ref> <remote sha>
z40=0000000000000000000000000000000000000000

while read local_ref local_sha remote_ref remote_sha
do
    if [ "$local_sha" = "$z40" ]; then
        # Handle delete
        print_warning "Branch deletion detected, skipping checks"
        exit 0
    else
        if [ "$remote_sha" = "$z40" ]; then
            # New branch, examine all commits
            range="$local_sha"
        else
            # Update to existing branch, examine new commits
            range="$remote_sha..$local_sha"
        fi

        # Get branch name
        branch_name=$(echo "$local_ref" | sed 's/refs\/heads\///')
        print_info "Pushing branch: $branch_name"
        print_info "Commit range: $range"
    fi
done

# ============================================================================
# CHECK 1: Run Full Test Suite
# ============================================================================

print_header "Running Test Suite"

if command -v just >/dev/null 2>&1; then
    print_info "Running 'just test'..."

    if just test; then
        print_success "All tests passed"
    else
        print_error "Test suite failed"
        print_info "Fix failing tests before pushing"
        exit 1
    fi
else
    print_warning "'just' command not found, skipping test suite"

    # Fallback to npm test
    if [ -f "package.json" ]; then
        print_info "Running 'npm test'..."
        if npm test; then
            print_success "npm tests passed"
        else
            print_error "npm tests failed"
            exit 1
        fi
    fi
fi

# ============================================================================
# CHECK 2: Security Vulnerability Scan
# ============================================================================

print_header "Security Vulnerability Scan"

if command -v npm >/dev/null 2>&1 && [ -f "package.json" ]; then
    print_info "Running 'npm audit'..."

    # Run npm audit and capture output
    if npm audit --audit-level=high; then
        print_success "No high/critical vulnerabilities found"
    else
        print_error "Security vulnerabilities detected"
        print_info "Run 'npm audit fix' to attempt automatic fixes"
        print_info "Or review and address vulnerabilities manually"
        exit 1
    fi
else
    print_warning "npm not available, skipping security audit"
fi

# Check for Haskell dependencies (if cabal is available)
if command -v cabal >/dev/null 2>&1; then
    print_info "Checking Haskell dependencies..."

    if [ -d "TOOLS/validation/haskell" ]; then
        cd TOOLS/validation/haskell

        # Check for outdated dependencies
        if cabal outdated 2>/dev/null; then
            print_warning "Some Haskell dependencies may be outdated"
            print_info "Review output and update if necessary"
        fi

        cd - >/dev/null
    fi

    print_success "Haskell dependency check completed"
fi

# ============================================================================
# CHECK 3: Build Verification
# ============================================================================

print_header "Build Verification"

if command -v just >/dev/null 2>&1; then
    print_info "Running 'just build'..."

    if just build; then
        print_success "Build successful"
    else
        print_error "Build failed"
        print_info "Fix build errors before pushing"
        exit 1
    fi
else
    print_warning "'just' command not found, skipping build verification"

    # Fallback to npm build
    if [ -f "package.json" ]; then
        print_info "Running 'npm run build'..."
        if npm run build 2>/dev/null; then
            print_success "npm build successful"
        else
            print_info "npm build script not found or failed (non-critical)"
        fi
    fi
fi

# ============================================================================
# CHECK 4: RSR Compliance Check
# ============================================================================

print_header "RSR Compliance Check"

if command -v just >/dev/null 2>&1; then
    print_info "Running 'just rsr-check'..."

    if just rsr-check; then
        print_success "RSR compliance check passed"
    else
        print_error "RSR compliance check failed"
        print_info "Ensure all required files are present:"
        print_info "  - CLAUDE.md"
        print_info "  - MAINTAINERS.md"
        print_info "  - TPCF.md"
        print_info "  - .well-known/security.txt"
        print_info "  - .well-known/ai.txt"
        print_info "  - .well-known/humans.txt"
        exit 1
    fi
else
    print_warning "'just' command not found, skipping RSR check"

    # Manual RSR check
    print_info "Performing manual RSR file check..."

    REQUIRED_FILES="CLAUDE.md MAINTAINERS.md TPCF.md .well-known/security.txt .well-known/ai.txt .well-known/humans.txt CHANGELOG.md GOVERNANCE.md CONTRIBUTING.md CODE_OF_PRACTICE.md SECURITY.md"

    MISSING_FILES=0
    for file in $REQUIRED_FILES; do
        if [ ! -f "$file" ]; then
            print_error "Missing required file: $file"
            MISSING_FILES=1
        fi
    done

    if [ $MISSING_FILES -eq 0 ]; then
        print_success "All RSR required files present"
    else
        print_error "RSR compliance check failed (missing files)"
        exit 1
    fi
fi

# ============================================================================
# CHECK 5: Validation (Linting, Links, Licenses)
# ============================================================================

print_header "Validation Checks"

if command -v just >/dev/null 2>&1; then
    print_info "Running 'just validate'..."

    if just validate; then
        print_success "Validation checks passed"
    else
        print_error "Validation failed"
        print_info "Run 'just format' to fix formatting issues"
        exit 1
    fi
else
    print_warning "'just' command not found, skipping validation"

    # Run prettier check if available
    if command -v npx >/dev/null 2>&1; then
        print_info "Running prettier check..."
        if npx prettier --check "**/*.md" "**/*.json" 2>/dev/null; then
            print_success "Formatting check passed"
        else
            print_error "Formatting issues detected"
            print_info "Run 'npm run format' to fix"
            exit 1
        fi
    fi
fi

# ============================================================================
# CHECK 6: Branch Protection (main/master)
# ============================================================================

print_header "Branch Protection Check"

# Check if pushing to protected branches
if [ "$branch_name" = "main" ] || [ "$branch_name" = "master" ]; then
    print_warning "Pushing to protected branch: $branch_name"

    # Check if there are any force push flags (--force, -f)
    # Note: This check is limited as flags are not passed to pre-push hook
    print_info "Ensure you have the right to push to $branch_name"
    print_info "Consider using a pull request workflow instead"

    # In production, you might want to prevent direct pushes to main/master
    # Uncomment the following lines to enforce this:
    # print_error "Direct pushes to $branch_name are not allowed"
    # print_info "Please create a pull request instead"
    # exit 1
fi

# ============================================================================
# CHECK 7: Commit Message Validation
# ============================================================================

print_header "Commit Message Validation"

print_info "Checking commit messages in range: $range"

# Get commit messages
if [ -n "$range" ]; then
    commits=$(git log --format="%s" "$range" 2>/dev/null)

    if [ -n "$commits" ]; then
        echo "$commits" | while read -r commit_msg; do
            # Check for minimum length
            msg_length=$(echo "$commit_msg" | wc -c)
            if [ "$msg_length" -lt 10 ]; then
                print_warning "Short commit message: '$commit_msg'"
            fi

            # Check for conventional commit format (optional)
            # Formats: feat:, fix:, docs:, style:, refactor:, test:, chore:
            if echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?:"; then
                print_success "Conventional commit format: $commit_msg"
            fi
        done
    fi
fi

print_success "Commit message validation completed"

# ============================================================================
# CHECK 8: CHANGELOG Update (for version branches)
# ============================================================================

print_header "CHANGELOG Check"

if echo "$branch_name" | grep -qE "^(release|v[0-9]+\.[0-9]+)"; then
    print_info "Version branch detected: $branch_name"

    # Check if CHANGELOG.md was updated
    if git diff --name-only "$range" 2>/dev/null | grep -q "CHANGELOG.md"; then
        print_success "CHANGELOG.md updated"
    else
        print_warning "CHANGELOG.md not updated"
        print_info "Consider updating CHANGELOG.md for release branches"
    fi
fi

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

print_header "Pre-push Validation Complete"

print_success "All checks passed!"
print_info "Safe to push to $remote"

echo ""
print_info "Summary:"
echo "  ✓ Tests passed"
echo "  ✓ No security vulnerabilities"
echo "  ✓ Build successful"
echo "  ✓ RSR compliant"
echo "  ✓ Validation passed"

echo ""
print_success "Proceeding with push..."

exit 0
