#!/usr/bin/env bash
# Synor Profiling Script
# Generates flamegraphs and performance profiles for critical paths

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PROFILE_DIR="$PROJECT_ROOT/target/profiles"

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

info() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }

# Check dependencies
check_deps() {
    info "Checking profiling dependencies..."

    # Check for cargo-flamegraph
    if ! command -v cargo-flamegraph &> /dev/null; then
        warn "cargo-flamegraph not found. Installing..."
        cargo install flamegraph
    fi

    # Check for samply (alternative profiler)
    if ! command -v samply &> /dev/null; then
        warn "samply not found. Install with: cargo install samply"
    fi

    # macOS: check for dtrace access
    if [[ "$OSTYPE" == "darwin"* ]]; then
        if ! csrutil status 2>/dev/null | grep -q "disabled"; then
            warn "On macOS, you may need to disable SIP for dtrace-based profiling"
            warn "Alternative: use 'samply' which uses the Instruments profiler"
        fi
    fi

    success "Dependencies checked"
}

# Build with profiling symbols
build_profile() {
    info "Building with profiling profile..."
    cd "$PROJECT_ROOT"
    cargo build --profile profiling --workspace
    success "Build complete"
}

# Profile kHeavyHash mining
profile_mining() {
    info "Profiling kHeavyHash mining..."
    mkdir -p "$PROFILE_DIR/mining"

    cd "$PROJECT_ROOT"

    # Run mining benchmark with flamegraph
    if command -v cargo-flamegraph &> /dev/null; then
        CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \
            --bench mining_bench \
            -p synor-mining \
            --output "$PROFILE_DIR/mining/flamegraph.svg" \
            -- --bench "kheavyhash"
        success "Mining flamegraph saved to $PROFILE_DIR/mining/flamegraph.svg"
    else
        # Fallback to regular benchmark with timing
        cargo bench -p synor-mining --bench mining_bench -- --verbose
    fi
}

# Profile GHOSTDAG consensus
profile_ghostdag() {
    info "Profiling GHOSTDAG consensus..."
    mkdir -p "$PROFILE_DIR/ghostdag"

    cd "$PROJECT_ROOT"

    if command -v cargo-flamegraph &> /dev/null; then
        CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \
            --bench ghostdag_bench \
            -p synor-dag \
            --output "$PROFILE_DIR/ghostdag/flamegraph.svg" \
            -- --bench
        success "GHOSTDAG flamegraph saved to $PROFILE_DIR/ghostdag/flamegraph.svg"
    else
        cargo bench -p synor-dag --bench ghostdag_bench -- --verbose
    fi
}

# Profile storage operations
profile_storage() {
    info "Profiling storage operations..."
    mkdir -p "$PROFILE_DIR/storage"

    cd "$PROJECT_ROOT"

    if command -v cargo-flamegraph &> /dev/null; then
        CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \
            --bench storage_bench \
            -p synor-storage \
            --output "$PROFILE_DIR/storage/flamegraph.svg" \
            -- --bench
        success "Storage flamegraph saved to $PROFILE_DIR/storage/flamegraph.svg"
    else
        cargo bench -p synor-storage --bench storage_bench -- --verbose
    fi
}

# Profile crypto operations
profile_crypto() {
    info "Profiling crypto operations..."
    mkdir -p "$PROFILE_DIR/crypto"

    cd "$PROJECT_ROOT"

    if command -v cargo-flamegraph &> /dev/null; then
        CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \
            --bench crypto_bench \
            -p synor-crypto \
            --output "$PROFILE_DIR/crypto/flamegraph.svg" \
            -- --bench
        success "Crypto flamegraph saved to $PROFILE_DIR/crypto/flamegraph.svg"
    else
        cargo bench -p synor-crypto --bench crypto_bench -- --verbose
    fi
}

# Profile consensus validation
profile_consensus() {
    info "Profiling consensus validation..."
    mkdir -p "$PROFILE_DIR/consensus"

    cd "$PROJECT_ROOT"

    if command -v cargo-flamegraph &> /dev/null; then
        CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \
            --bench consensus_bench \
            -p synor-consensus \
            --output "$PROFILE_DIR/consensus/flamegraph.svg" \
            -- --bench
        success "Consensus flamegraph saved to $PROFILE_DIR/consensus/flamegraph.svg"
    else
        cargo bench -p synor-consensus --bench consensus_bench -- --verbose
    fi
}

# Run all benchmarks and compare
run_all_benchmarks() {
    info "Running all benchmarks..."
    cd "$PROJECT_ROOT"

    # Create baseline if it doesn't exist
    if [[ ! -d "$PROFILE_DIR/baseline" ]]; then
        info "Creating baseline benchmark results..."
        cargo bench --workspace -- --save-baseline baseline
        success "Baseline saved"
    else
        info "Comparing against baseline..."
        cargo bench --workspace -- --baseline baseline
    fi
}

# Profile with samply (macOS-friendly)
profile_with_samply() {
    local target="$1"

    if ! command -v samply &> /dev/null; then
        error "samply not installed. Run: cargo install samply"
    fi

    info "Profiling $target with samply..."
    mkdir -p "$PROFILE_DIR/samply"

    cd "$PROJECT_ROOT"

    case "$target" in
        mining)
            samply record -- cargo bench -p synor-mining --bench mining_bench
            ;;
        ghostdag)
            samply record -- cargo bench -p synor-dag --bench ghostdag_bench
            ;;
        storage)
            samply record -- cargo bench -p synor-storage --bench storage_bench
            ;;
        crypto)
            samply record -- cargo bench -p synor-crypto --bench crypto_bench
            ;;
        consensus)
            samply record -- cargo bench -p synor-consensus --bench consensus_bench
            ;;
        *)
            error "Unknown target: $target"
            ;;
    esac
}

# Generate summary report
generate_report() {
    info "Generating profiling report..."

    local report="$PROFILE_DIR/PROFILING_REPORT.md"

    cat > "$report" << 'EOF'
# Synor Profiling Report

Generated: $(date)

## Critical Paths Analyzed

### 1. kHeavyHash Mining
- Matrix initialization time
- Hash computation throughput
- Memory allocation patterns

### 2. GHOSTDAG Consensus
- Block ordering performance
- Blue score calculation
- Merge set computation

### 3. Storage Operations
- RocksDB read/write latency
- Batch operation efficiency
- Cache hit rates

### 4. Cryptography
- Ed25519 signing/verification
- Dilithium3 operations
- Hybrid signature performance

## Flamegraphs

See SVG files in subdirectories:
- `mining/flamegraph.svg`
- `ghostdag/flamegraph.svg`
- `storage/flamegraph.svg`
- `crypto/flamegraph.svg`
- `consensus/flamegraph.svg`

## Optimization Opportunities

1. **Hot paths** - Look for wide bars at the top of flamegraphs
2. **Allocation pressure** - Search for `alloc` or `malloc` patterns
3. **Lock contention** - Look for mutex/rwlock wait times
4. **Serialization overhead** - Check borsh/serde time

## Running Profiles

```bash
# Profile specific component
./scripts/profile.sh mining
./scripts/profile.sh ghostdag
./scripts/profile.sh storage

# Run all benchmarks with comparison
./scripts/profile.sh all

# Use samply on macOS
./scripts/profile.sh samply mining
```
EOF

    success "Report generated at $report"
}

# Print usage
usage() {
    cat << EOF
Usage: $0 <command> [options]

Commands:
    check       Check profiling dependencies
    build       Build with profiling symbols
    mining      Profile kHeavyHash mining
    ghostdag    Profile GHOSTDAG consensus
    storage     Profile storage operations
    crypto      Profile cryptographic operations
    consensus   Profile consensus validation
    all         Run all benchmarks
    samply      Profile with samply (macOS-friendly)
    report      Generate profiling report

Options:
    -h, --help  Show this help message

Examples:
    $0 check                    # Check dependencies
    $0 mining                   # Profile mining
    $0 samply ghostdag          # Profile GHOSTDAG with samply
    $0 all                      # Run all benchmarks
EOF
}

# Main entry point
main() {
    case "${1:-}" in
        check)
            check_deps
            ;;
        build)
            build_profile
            ;;
        mining)
            check_deps
            profile_mining
            ;;
        ghostdag)
            check_deps
            profile_ghostdag
            ;;
        storage)
            check_deps
            profile_storage
            ;;
        crypto)
            check_deps
            profile_crypto
            ;;
        consensus)
            check_deps
            profile_consensus
            ;;
        all)
            check_deps
            run_all_benchmarks
            ;;
        samply)
            profile_with_samply "${2:-}"
            ;;
        report)
            generate_report
            ;;
        -h|--help|"")
            usage
            ;;
        *)
            error "Unknown command: $1"
            ;;
    esac
}

main "$@"
