#!/bin/bash
set -euo pipefail

# Coverage Enforcement Script for Foxhunt HFT System
# Enforces 60% minimum coverage, 75% target for production modules
# Generates JSON and HTML reports, calculates per-module coverage

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

# Coverage thresholds
MIN_COVERAGE=60
TARGET_COVERAGE=75
PRODUCTION_COVERAGE=75

# Output files
COVERAGE_JSON="coverage_report.json"
COVERAGE_HTML="coverage_html"
MODULE_REPORT="module_coverage.json"

# Production modules (higher threshold)
PRODUCTION_MODULES=(
    "trading_engine"
    "risk"
    "config"
    "common"
    "services/trading_service"
    "services/api"
)

# Print colored message
print_message() {
    local color=$1
    local message=$2
    echo -e "${color}${message}${NC}"
}

# Print section header
print_header() {
    echo ""
    print_message "$BLUE" "================================"
    print_message "$BLUE" "$1"
    print_message "$BLUE" "================================"
}

# Check if cargo-llvm-cov is installed
check_dependencies() {
    print_header "Checking Dependencies"

    if ! command -v cargo-llvm-cov &> /dev/null; then
        print_message "$RED" "Error: cargo-llvm-cov not found"
        print_message "$YELLOW" "Install with: cargo install cargo-llvm-cov"
        exit 1
    fi

    if ! command -v jq &> /dev/null; then
        print_message "$RED" "Error: jq not found"
        print_message "$YELLOW" "Install with: sudo apt-get install jq (Ubuntu/Debian) or brew install jq (macOS)"
        exit 1
    fi

    if ! command -v bc &> /dev/null; then
        print_message "$RED" "Error: bc not found"
        print_message "$YELLOW" "Install with: sudo apt-get install bc (Ubuntu/Debian) or brew install bc (macOS)"
        exit 1
    fi

    print_message "$GREEN" "✓ cargo-llvm-cov found: $(cargo-llvm-cov --version)"
    print_message "$GREEN" "✓ jq found: $(jq --version)"
    print_message "$GREEN" "✓ bc found: $(bc --version | head -1)"
}

# Clean previous coverage data
clean_coverage() {
    print_header "Cleaning Previous Coverage Data"

    find . -name "*.profraw" -delete 2>/dev/null || true
    rm -rf "$COVERAGE_HTML" 2>/dev/null || true
    rm -f "$COVERAGE_JSON" 2>/dev/null || true
    rm -f "$MODULE_REPORT" 2>/dev/null || true
    rm -f lcov.info 2>/dev/null || true

    print_message "$GREEN" "✓ Coverage data cleaned"
}

# Run comprehensive coverage analysis
run_coverage() {
    print_header "Running Coverage Analysis"

    print_message "$YELLOW" "Running tests with coverage instrumentation..."
    print_message "$YELLOW" "This may take several minutes..."

    # Run coverage with HTML output (primary run with tests)
    print_message "$YELLOW" "Generating HTML report (running tests)..."
    if ! timeout 600 cargo llvm-cov --workspace \
        --all-features \
        --html \
        --exclude examples \
        --exclude benchmarks \
        --output-dir "$COVERAGE_HTML" 2>&1 | tee coverage_output.log; then

        print_message "$RED" "Error: Coverage analysis failed"
        print_message "$YELLOW" "Check coverage_output.log for details"
        exit 1
    fi

    # Generate LCOV report (reuses cached coverage data)
    print_message "$YELLOW" "Generating LCOV report..."
    if ! timeout 600 cargo llvm-cov --workspace \
        --all-features \
        --no-run \
        --lcov \
        --exclude examples \
        --exclude benchmarks \
        --output-path lcov.info 2>&1 | tee -a coverage_output.log; then

        print_message "$YELLOW" "Warning: LCOV generation failed"
    fi

    # Generate JSON report (reuses cached coverage data)
    print_message "$YELLOW" "Generating JSON report..."
    if ! timeout 600 cargo llvm-cov --workspace \
        --all-features \
        --no-run \
        --json \
        --exclude examples \
        --exclude benchmarks \
        --output-path "$COVERAGE_JSON" 2>&1 | tee -a coverage_output.log; then

        print_message "$YELLOW" "Warning: JSON generation failed, coverage will be extracted from HTML"
    fi

    print_message "$GREEN" "✓ Coverage analysis complete"
}

# Extract overall coverage percentage
extract_coverage() {
    print_header "Extracting Coverage Metrics"

    # Try to extract from JSON first (most reliable)
    if [ -f "$COVERAGE_JSON" ]; then
        local lines_covered=$(jq '.data[0].totals.lines.covered' "$COVERAGE_JSON" 2>/dev/null || echo "null")
        local lines_total=$(jq '.data[0].totals.lines.count' "$COVERAGE_JSON" 2>/dev/null || echo "null")

        # Handle null values from empty or malformed JSON
        if [ "$lines_covered" == "null" ] || [ "$lines_total" == "null" ]; then
            print_message "$YELLOW" "Warning: JSON coverage data is empty or malformed, trying alternative methods..."
        elif [ "$lines_total" != "0" ] && [ "$lines_total" != "1" ]; then
            # Protect against division by zero
            if [ "$lines_total" -gt 0 ] 2>/dev/null; then
                COVERAGE_PERCENT=$(echo "scale=2; ($lines_covered * 100) / $lines_total" | bc -l)
                print_message "$GREEN" "✓ Coverage extracted from JSON: ${COVERAGE_PERCENT}%"
                return 0
            fi
        fi
    fi

    # Fallback to lcov parsing
    if [ -f lcov.info ]; then
        local lines_found=$(grep -o 'LF:[0-9]*' lcov.info 2>/dev/null | cut -d: -f2 | paste -sd+ | bc 2>/dev/null || echo "0")
        local lines_hit=$(grep -o 'LH:[0-9]*' lcov.info 2>/dev/null | cut -d: -f2 | paste -sd+ | bc 2>/dev/null || echo "0")

        # Protect against division by zero
        if [ "$lines_found" != "0" ] && [ "$lines_found" -gt 0 ] 2>/dev/null; then
            COVERAGE_PERCENT=$(echo "scale=2; ($lines_hit * 100) / $lines_found" | bc -l)
            print_message "$GREEN" "✓ Coverage extracted from LCOV: ${COVERAGE_PERCENT}%"
            return 0
        fi
    fi

    # Fallback to summary output
    COVERAGE_PERCENT=$(cargo llvm-cov --workspace --all-features --summary-only 2>/dev/null | grep -o '[0-9.]*%' | head -1 | tr -d '%' || echo "0")

    if [ "$COVERAGE_PERCENT" == "0" ] || [ -z "$COVERAGE_PERCENT" ]; then
        print_message "$RED" "Error: Could not extract coverage percentage from any source"
        print_message "$YELLOW" "Checked: JSON report, LCOV file, and summary output"
        exit 1
    fi

    print_message "$GREEN" "✓ Coverage extracted: ${COVERAGE_PERCENT}%"
}

# Calculate per-module coverage
calculate_module_coverage() {
    print_header "Calculating Per-Module Coverage"

    # Initialize JSON array
    echo "[" > "$MODULE_REPORT"
    local first=true

    # Get list of workspace members
    local members=$(cargo metadata --no-deps --format-version 1 | jq -r '.workspace_members[]' | cut -d' ' -f1)

    for package in $members; do
        print_message "$YELLOW" "Analyzing package: $package"

        # Run coverage for single package
        local pkg_coverage=$(cargo llvm-cov --package "$package" --all-features --summary-only 2>/dev/null | grep -o '[0-9.]*%' | head -1 | tr -d '%' || echo "0.0")

        # Handle empty or invalid coverage values
        if [ -z "$pkg_coverage" ] || ! [[ "$pkg_coverage" =~ ^[0-9.]+$ ]]; then
            print_message "$YELLOW" "  Warning: Could not extract coverage for $package, defaulting to 0.0%"
            pkg_coverage="0.0"
        fi

        # Determine if this is a production module
        local is_production=false
        for prod_module in "${PRODUCTION_MODULES[@]}"; do
            if [[ "$package" == *"$prod_module"* ]]; then
                is_production=true
                break
            fi
        done

        # Determine threshold
        local threshold=$MIN_COVERAGE
        if [ "$is_production" = true ]; then
            threshold=$PRODUCTION_COVERAGE
        fi

        # Determine status (using bc -l for floating-point comparison)
        local status="PASS"
        local color="$GREEN"
        if (( $(echo "$pkg_coverage < $threshold" | bc -l) )); then
            status="FAIL"
            color="$RED"
        elif (( $(echo "$pkg_coverage < $TARGET_COVERAGE" | bc -l) )); then
            status="WARN"
            color="$YELLOW"
        fi

        # Add comma separator
        if [ "$first" = false ]; then
            echo "," >> "$MODULE_REPORT"
        fi
        first=false

        # Write JSON entry
        cat >> "$MODULE_REPORT" << EOF
  {
    "package": "$package",
    "coverage": $pkg_coverage,
    "threshold": $threshold,
    "is_production": $is_production,
    "status": "$status"
  }
EOF

        print_message "$color" "  $package: ${pkg_coverage}% (threshold: ${threshold}%) - $status"
    done

    echo "]" >> "$MODULE_REPORT"
    print_message "$GREEN" "✓ Module coverage report saved to $MODULE_REPORT"
}

# Generate coverage summary
generate_summary() {
    print_header "Coverage Summary"

    # Determine overall status
    local status="PASS"
    local color="$GREEN"
    local badge_color="brightgreen"

    if (( $(echo "$COVERAGE_PERCENT < $MIN_COVERAGE" | bc -l) )); then
        status="FAIL"
        color="$RED"
        badge_color="red"
    elif (( $(echo "$COVERAGE_PERCENT < $TARGET_COVERAGE" | bc -l) )); then
        status="WARN"
        color="$YELLOW"
        badge_color="yellow"
    fi

    # Print summary
    print_message "$color" "Overall Coverage: ${COVERAGE_PERCENT}%"
    print_message "$BLUE" "Minimum Required: ${MIN_COVERAGE}%"
    print_message "$BLUE" "Target Coverage: ${TARGET_COVERAGE}%"
    print_message "$color" "Status: $status"

    # Generate badge markdown
    local badge_url="https://img.shields.io/badge/coverage-${COVERAGE_PERCENT}%25-${badge_color}"
    echo "![Coverage Badge]($badge_url)" > coverage_badge.md

    # Generate detailed summary for PR comments
    cat > coverage_summary.md << EOF
## 📊 Code Coverage Report

**Overall Coverage**: ${COVERAGE_PERCENT}%
**Minimum Required**: ${MIN_COVERAGE}%
**Target**: ${TARGET_COVERAGE}%
**Status**: $status

![Coverage Badge]($badge_url)

### Module Coverage Breakdown

| Module | Coverage | Threshold | Status |
|--------|----------|-----------|--------|
EOF

    # Add module rows
    jq -r '.[] | "| \(.package) | \(.coverage)% | \(.threshold)% | \(.status) |"' "$MODULE_REPORT" >> coverage_summary.md

    cat >> coverage_summary.md << EOF

### Coverage Targets

- **Production Modules** (Trading Engine, Risk, API Gateway): ${PRODUCTION_COVERAGE}%
- **Core Modules** (Config, Common, Data): ${TARGET_COVERAGE}%
- **Supporting Modules** (Tests, Utilities): ${MIN_COVERAGE}%

[📈 View Detailed HTML Report](./coverage_html/index.html)
EOF

    print_message "$GREEN" "✓ Coverage summary generated"
}

# Check coverage thresholds
check_thresholds() {
    print_header "Checking Coverage Thresholds"

    local failed_modules=()

    # Check each module
    while IFS= read -r module; do
        local package=$(echo "$module" | jq -r '.package')
        local coverage=$(echo "$module" | jq -r '.coverage')
        local threshold=$(echo "$module" | jq -r '.threshold')
        local status=$(echo "$module" | jq -r '.status')

        if [ "$status" = "FAIL" ]; then
            failed_modules+=("$package (${coverage}% < ${threshold}%)")
        fi
    done < <(jq -c '.[]' "$MODULE_REPORT")

    # Check overall coverage
    if (( $(echo "$COVERAGE_PERCENT < $MIN_COVERAGE" | bc -l) )); then
        print_message "$RED" "✗ Overall coverage ${COVERAGE_PERCENT}% is below minimum ${MIN_COVERAGE}%"

        if [ ${#failed_modules[@]} -gt 0 ]; then
            print_message "$RED" "Failed modules:"
            for module in "${failed_modules[@]}"; do
                print_message "$RED" "  - $module"
            done
        fi

        exit 1
    fi

    if [ ${#failed_modules[@]} -gt 0 ]; then
        print_message "$YELLOW" "⚠ Some modules below their thresholds (non-blocking):"
        for module in "${failed_modules[@]}"; do
            print_message "$YELLOW" "  - $module"
        done
    fi

    print_message "$GREEN" "✓ Coverage thresholds met"
}

# Generate coverage artifacts
generate_artifacts() {
    print_header "Generating Coverage Artifacts"

    # Create artifacts directory
    mkdir -p coverage_artifacts

    # Copy reports
    cp -r "$COVERAGE_HTML" coverage_artifacts/ 2>/dev/null || true
    cp lcov.info coverage_artifacts/ 2>/dev/null || true
    cp "$COVERAGE_JSON" coverage_artifacts/ 2>/dev/null || true
    cp "$MODULE_REPORT" coverage_artifacts/ 2>/dev/null || true
    cp coverage_summary.md coverage_artifacts/ 2>/dev/null || true
    cp coverage_badge.md coverage_artifacts/ 2>/dev/null || true

    # Generate index page
    cat > coverage_artifacts/index.html << EOF
<!DOCTYPE html>
<html>
<head>
    <title>Foxhunt Coverage Report</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        h1 { color: #333; }
        .metric { font-size: 24px; font-weight: bold; }
        .pass { color: green; }
        .warn { color: orange; }
        .fail { color: red; }
        table { border-collapse: collapse; width: 100%; margin-top: 20px; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #4CAF50; color: white; }
    </style>
</head>
<body>
    <h1>Foxhunt Code Coverage Report</h1>
    <div class="metric">Overall Coverage: <span class="$([ "$status" = "PASS" ] && echo "pass" || echo "warn")">${COVERAGE_PERCENT}%</span></div>
    <p>Generated: $(date)</p>
    <ul>
        <li><a href="coverage_html/index.html">Detailed HTML Report</a></li>
        <li><a href="module_coverage.json">Module Coverage JSON</a></li>
        <li><a href="coverage_summary.md">Coverage Summary</a></li>
    </ul>
</body>
</html>
EOF

    print_message "$GREEN" "✓ Coverage artifacts generated in coverage_artifacts/"
}

# Main execution
main() {
    print_header "Foxhunt Coverage Enforcement"

    check_dependencies
    clean_coverage
    run_coverage
    extract_coverage
    calculate_module_coverage
    generate_summary
    generate_artifacts
    check_thresholds

    print_header "Coverage Analysis Complete"
    print_message "$GREEN" "✓ All checks passed!"
}

# Run main function
main "$@"
