#!/bin/bash

# OpenCrates Comprehensive Build, Test & Deployment Automation
# This script provides end-to-end automation for building, testing, securing, and deploying OpenCrates

set -euo pipefail

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
BUILD_DIR="${PROJECT_ROOT}/target"
REPORTS_DIR="${PROJECT_ROOT}/reports"
DOCKER_REGISTRY="${DOCKER_REGISTRY:-ghcr.io/opencrates}"
VERSION="${VERSION:-$(git describe --tags --always --dirty)}"
ENVIRONMENT="${ENVIRONMENT:-development}"

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

# Logging functions
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Cleanup function
cleanup() {
    log_info "Cleaning up temporary files..."
    rm -rf /tmp/opencrates-build-*
}

trap cleanup EXIT

# Initialize build environment
init_build_env() {
    log_info "Initializing build environment..."
    
    # Create necessary directories
    mkdir -p "$REPORTS_DIR"/{coverage,security,performance,quality}
    mkdir -p "$BUILD_DIR"/{debug,release,docker}
    
    # Set environment variables
    export RUST_BACKTRACE=1
    export CARGO_INCREMENTAL=0
    # Only set coverage flags for nightly builds
    if rustc --version | grep -q "nightly"; then
        export RUSTFLAGS="-Zinstrument-coverage"
        export LLVM_PROFILE_FILE="coverage-%p-%m.profraw"
    fi
    
    # Install required tools
    install_build_tools
    
    log_success "Build environment initialized"
}

# Install required build tools
install_build_tools() {
    log_info "Installing build tools..."
    
    # Rust tools
    if ! command -v cargo-audit &> /dev/null; then
        cargo install cargo-audit || log_warning "Failed to install cargo-audit"
    fi
    
    if ! command -v cargo-tarpaulin &> /dev/null; then
        cargo install cargo-tarpaulin || log_warning "Failed to install cargo-tarpaulin"
    fi
    
    if ! command -v cargo-criterion &> /dev/null; then
        cargo install cargo-criterion || log_warning "Failed to install cargo-criterion"
    fi
    
    if ! command -v cargo-deny &> /dev/null; then
        cargo install cargo-deny || log_warning "Failed to install cargo-deny"
    fi
    
    if ! command -v cargo-outdated &> /dev/null; then
        cargo install cargo-outdated || log_warning "Failed to install cargo-outdated"
    fi
    
    if ! command -v cargo-bloat &> /dev/null; then
        cargo install cargo-bloat || log_warning "Failed to install cargo-bloat"
    fi
    
    # Security tools
    if ! command -v semgrep &> /dev/null && command -v pip &> /dev/null; then
        pip install semgrep
    fi
    
    # Docker tools
    if ! command -v hadolint &> /dev/null; then
        log_warning "hadolint not found, skipping Dockerfile linting"
    fi
    
    # Kubernetes tools
    if ! command -v kubeval &> /dev/null; then
        log_warning "kubeval not found, skipping Kubernetes manifest validation"
    fi
    
    log_success "Build tools installed"
}

# Pre-build checks and setup
pre_build_checks() {
    log_info "Running pre-build checks..."
    
    # Check Rust version
    local rust_version
    rust_version=$(rustc --version | cut -d' ' -f2)
    log_info "Using Rust version: $rust_version"
    
    # Check dependencies
    log_info "Checking dependencies..."
    cargo tree --duplicates || log_warning "Duplicate dependencies found"
    
    # Check for outdated dependencies
    log_info "Checking for outdated dependencies..."
    cargo outdated || log_warning "Some dependencies are outdated"
    
    # Validate Cargo.toml
    cargo check --all-targets --all-features
    
    log_success "Pre-build checks completed"
}

# Code formatting and linting
format_and_lint() {
    log_info "Running code formatting and linting..."
    
    # Format code
    log_info "Formatting code with rustfmt..."
    cargo fmt --all -- --check || {
        log_warning "Code formatting issues found, auto-fixing..."
        cargo fmt --all
    }
    
    # Run clippy
    log_info "Running clippy lints..."
    cargo clippy --all-targets --all-features -- -D warnings -D clippy::all -W clippy::pedantic \
        --report-format json > "$REPORTS_DIR/quality/clippy-report.json" || {
        log_error "Clippy found issues"
        return 1
    }
    
    # Additional linting with semgrep (if available)
    if command -v semgrep &> /dev/null; then
        log_info "Running semgrep security analysis..."
        semgrep --config=auto --json --output="$REPORTS_DIR/security/semgrep-report.json" . || {
            log_warning "Semgrep found potential issues"
        }
    fi
    
    log_success "Code formatting and linting completed"
}

# Security auditing
security_audit() {
    log_info "Running security audit..."
    
    # Cargo audit for vulnerable dependencies
    log_info "Checking for vulnerable dependencies..."
    cargo audit --json > "$REPORTS_DIR/security/audit-report.json" || {
        log_error "Security vulnerabilities found in dependencies"
        return 1
    }
    
    # Cargo deny for license and dependency policies
    log_info "Checking license and dependency policies..."
    cargo deny --log-level warn check --format json > "$REPORTS_DIR/security/deny-report.json" || {
        log_warning "Policy violations found"
    }
    
    # Static analysis with semgrep
    if command -v semgrep &> /dev/null; then
        log_info "Running advanced security analysis..."
        semgrep --config=p/security-audit --config=p/rust --json \
            --output="$REPORTS_DIR/security/semgrep-security.json" . || {
            log_warning "Security analysis completed with findings"
        }
    fi
    
    log_success "Security audit completed"
}

# Build the project
build_project() {
    log_info "Building OpenCrates..."
    
    # Clean previous builds
    cargo clean
    
    # Build in debug mode for testing
    log_info "Building debug version..."
    cargo build --all-targets --all-features
    
    # Build in release mode for deployment
    log_info "Building release version..."
    cargo build --release --all-targets --all-features
    
    # Check binary sizes
    log_info "Analyzing binary sizes..."
    cargo bloat --release --crates > "$REPORTS_DIR/quality/binary-sizes.txt"
    
    log_success "Build completed successfully"
}

# Run comprehensive tests
run_tests() {
    log_info "Running comprehensive test suite..."
    
    # Unit tests with coverage
    log_info "Running unit tests with coverage..."
    cargo tarpaulin --verbose --all-features --workspace --timeout 120 \
        --exclude-files "src/bin/*" --exclude-files "tests/*" \
        --out Html --out Xml --out Json \
        --output-dir "$REPORTS_DIR/coverage" || {
        log_error "Unit tests failed"
        return 1
    }
    
    # Integration tests
    log_info "Running integration tests..."
    cargo test --release --test '*' -- --test-threads=1 || {
        log_error "Integration tests failed"
        return 1
    }
    
    # Documentation tests
    log_info "Running documentation tests..."
    cargo test --doc || {
        log_error "Documentation tests failed"
        return 1
    }
    
    # Property-based tests (if available)
    if grep -r "proptest" Cargo.toml &> /dev/null; then
        log_info "Running property-based tests..."
        cargo test --features proptest || {
            log_warning "Property-based tests failed"
        }
    fi
    
    log_success "All tests completed successfully"
}

# Performance benchmarking
run_benchmarks() {
    log_info "Running performance benchmarks..."
    
    # Criterion benchmarks
    if [ -d "benches" ]; then
        log_info "Running criterion benchmarks..."
        cargo criterion --output-format html \
            --plotting-backend plotters > "$REPORTS_DIR/performance/benchmark-output.txt" || {
            log_warning "Some benchmarks failed"
        }
        
        # Move criterion reports
        if [ -d "target/criterion" ]; then
            cp -r target/criterion "$REPORTS_DIR/performance/"
        fi
    fi
    
    # Custom performance tests
    if [ -f "scripts/performance_tests.sh" ]; then
        log_info "Running custom performance tests..."
        bash scripts/performance_tests.sh > "$REPORTS_DIR/performance/custom-tests.txt" || {
            log_warning "Custom performance tests failed"
        }
    fi
    
    log_success "Performance benchmarking completed"
}

# Build Docker images
build_docker_images() {
    log_info "Building Docker images..."
    
    # Validate Dockerfile
    if command -v hadolint &> /dev/null; then
        log_info "Validating Dockerfile..."
        hadolint Dockerfile > "$REPORTS_DIR/quality/dockerfile-lint.txt" || {
            log_warning "Dockerfile linting issues found"
        }
    fi
    
    # Build multi-stage Docker image
    log_info "Building production Docker image..."
    docker build \
        --target runtime \
        --build-arg VERSION="$VERSION" \
        --build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
        --build-arg VCS_REF="$(git rev-parse HEAD)" \
        -t "${DOCKER_REGISTRY}/opencrates:${VERSION}" \
        -t "${DOCKER_REGISTRY}/opencrates:latest" \
        -f Dockerfile . || {
        log_error "Docker build failed"
        return 1
    }
    
    # Build development image
    log_info "Building development Docker image..."
    docker build \
        --target builder \
        -t "${DOCKER_REGISTRY}/opencrates:${VERSION}-dev" \
        -f Dockerfile . || {
        log_warning "Development Docker build failed"
    }
    
    # Security scan Docker images
    if command -v trivy &> /dev/null; then
        log_info "Scanning Docker image for vulnerabilities..."
        trivy image --format json --output "$REPORTS_DIR/security/docker-scan.json" \
            "${DOCKER_REGISTRY}/opencrates:${VERSION}" || {
            log_warning "Docker security scan found issues"
        }
    fi
    
    log_success "Docker images built successfully"
}

# Validate Kubernetes manifests
validate_k8s_manifests() {
    log_info "Validating Kubernetes manifests..."
    
    if command -v kubeval &> /dev/null && [ -f "docker/advanced-deployment.yml" ]; then
        log_info "Validating Kubernetes YAML..."
        kubeval docker/advanced-deployment.yml > "$REPORTS_DIR/quality/k8s-validation.txt" || {
            log_warning "Kubernetes manifest validation issues found"
        }
    fi
    
    # Additional validation with kubectl (if available and configured)
    if command -v kubectl &> /dev/null; then
        log_info "Performing kubectl validation..."
        kubectl apply --dry-run=client -f docker/advanced-deployment.yml > /dev/null || {
            log_warning "kubectl validation found issues"
        }
    fi
    
    log_success "Kubernetes manifests validated"
}

# Generate comprehensive reports
generate_reports() {
    log_info "Generating comprehensive reports..."
    
    # Create summary report
    cat > "$REPORTS_DIR/build-summary.md" << EOF
# OpenCrates Build Report

**Build Version:** $VERSION
**Build Date:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')
**Environment:** $ENVIRONMENT
**Git Commit:** $(git rev-parse HEAD)

## Build Status
- ✅ Code Formatting & Linting
- ✅ Security Audit
- ✅ Unit Tests
- ✅ Integration Tests
- ✅ Performance Benchmarks
- ✅ Docker Build
- ✅ Kubernetes Validation

## Coverage Report
$([ -f "$REPORTS_DIR/coverage/cobertura.xml" ] && echo "Coverage data available in coverage/cobertura.xml" || echo "No coverage data available")

## Security Report
$([ -f "$REPORTS_DIR/security/audit-report.json" ] && echo "Security audit completed - see security/ directory" || echo "No security audit data")

## Performance Report
$([ -d "$REPORTS_DIR/performance/criterion" ] && echo "Performance benchmarks completed - see performance/ directory" || echo "No performance data available")

## Artifacts
- Binary: target/release/opencrates
- Docker Image: ${DOCKER_REGISTRY}/opencrates:${VERSION}
- Reports: reports/ directory
EOF
    
    # Generate JSON summary for CI/CD systems
    cat > "$REPORTS_DIR/build-summary.json" << EOF
{
  "version": "$VERSION",
  "build_date": "$(date -u +'%Y-%m-%dT%H:%M:%SZ')",
  "environment": "$ENVIRONMENT",
  "git_commit": "$(git rev-parse HEAD)",
  "status": "success",
  "artifacts": {
    "binary": "target/release/opencrates",
    "docker_image": "${DOCKER_REGISTRY}/opencrates:${VERSION}",
    "reports_dir": "reports/"
  }
}
EOF
    
    log_success "Reports generated successfully"
}

# Deploy to environment
deploy() {
    local environment="$1"
    log_info "Deploying to $environment environment..."
    
    case "$environment" in
        "development"|"dev")
            deploy_development
            ;;
        "staging"|"stage")
            deploy_staging
            ;;
        "production"|"prod")
            deploy_production
            ;;
        *)
            log_error "Unknown environment: $environment"
            return 1
            ;;
    esac
    
    log_success "Deployment to $environment completed"
}

# Development deployment
deploy_development() {
    log_info "Deploying to development environment..."
    
    # Push to development registry
    docker push "${DOCKER_REGISTRY}/opencrates:${VERSION}-dev"
    
    # Apply development Kubernetes manifests
    if command -v kubectl &> /dev/null; then
        kubectl apply -f docker/advanced-deployment.yml -n opencrates-dev || {
            log_warning "Kubernetes deployment failed"
        }
    fi
}

# Staging deployment
deploy_staging() {
    log_info "Deploying to staging environment..."
    
    # Push to staging registry
    docker push "${DOCKER_REGISTRY}/opencrates:${VERSION}"
    
    # Apply staging Kubernetes manifests
    if command -v kubectl &> /dev/null; then
        kubectl apply -f docker/advanced-deployment.yml -n opencrates-staging || {
            log_warning "Kubernetes deployment failed"
        }
    fi
    
    # Run smoke tests
    run_smoke_tests "staging"
}

# Production deployment
deploy_production() {
    log_info "Deploying to production environment..."
    
    # Additional production checks
    if [ "$ENVIRONMENT" != "production" ]; then
        log_warning "Not in production environment, skipping production deployment"
        return 0
    fi
    
    # Push to production registry
    docker push "${DOCKER_REGISTRY}/opencrates:${VERSION}"
    docker push "${DOCKER_REGISTRY}/opencrates:latest"
    
    # Blue-green deployment to production
    if command -v kubectl &> /dev/null; then
        kubectl apply -f docker/advanced-deployment.yml -n opencrates-prod || {
            log_error "Production deployment failed"
            return 1
        }
        
        # Wait for rollout
        kubectl rollout status deployment/opencrates-deployment -n opencrates-prod --timeout=300s || {
            log_error "Production rollout failed"
            return 1
        }
    fi
    
    # Run comprehensive smoke tests
    run_smoke_tests "production"
}

# Run smoke tests
run_smoke_tests() {
    local environment="$1"
    log_info "Running smoke tests for $environment..."
    
    # Health check endpoints
    local base_url
    case "$environment" in
        "development")
            base_url="http://localhost:8080"
            ;;
        "staging")
            base_url="https://staging.opencrates.dev"
            ;;
        "production")
            base_url="https://opencrates.dev"
            ;;
    esac
    
    # Basic health check
    if command -v curl &> /dev/null; then
        log_info "Testing health endpoint..."
        curl -f "$base_url/health" > /dev/null || {
            log_error "Health check failed"
            return 1
        }
        
        log_info "Testing API endpoint..."
        curl -f "$base_url/api/v1/status" > /dev/null || {
            log_warning "API endpoint test failed"
        }
    fi
    
    log_success "Smoke tests completed"
}

# Main execution function
main() {
    local command="${1:-all}"
    
    log_info "Starting OpenCrates comprehensive build process..."
    log_info "Command: $command"
    log_info "Version: $VERSION"
    log_info "Environment: $ENVIRONMENT"
    
    case "$command" in
        "init")
            init_build_env
            ;;
        "check")
            init_build_env
            pre_build_checks
            ;;
        "format")
            format_and_lint
            ;;
        "security")
            security_audit
            ;;
        "build")
            init_build_env
            pre_build_checks
            format_and_lint
            build_project
            ;;
        "test")
            run_tests
            ;;
        "bench")
            run_benchmarks
            ;;
        "docker")
            build_docker_images
            ;;
        "deploy")
            deploy "${2:-development}"
            ;;
        "all")
            init_build_env
            pre_build_checks
            format_and_lint
            security_audit
            build_project
            run_tests
            run_benchmarks
            build_docker_images
            validate_k8s_manifests
            generate_reports
            ;;
        *)
            echo "Usage: $0 {init|check|format|security|build|test|bench|docker|deploy|all}"
            echo ""
            echo "Commands:"
            echo "  init     - Initialize build environment"
            echo "  check    - Run pre-build checks"
            echo "  format   - Format and lint code"
            echo "  security - Run security audit"
            echo "  build    - Build the project"
            echo "  test     - Run comprehensive tests"
            echo "  bench    - Run performance benchmarks"
            echo "  docker   - Build Docker images"
            echo "  deploy   - Deploy to environment (dev|staging|prod)"
            echo "  all      - Run complete build pipeline"
            exit 1
            ;;
    esac
    
    log_success "OpenCrates build process completed successfully!"
}

# Execute main function with all arguments
main "$@" 