#!/bin/bash

# Vulkan-Go Auto-Update Script
# This script automatically updates the Vulkan API definitions from the official Khronos repository
# and regenerates the Go bindings.

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
VULKAN_HEADERS_URL="https://github.com/KhronosGroup/Vulkan-Headers.git"
TEMP_DIR="$PROJECT_ROOT/.temp"
VULKAN_HEADERS_DIR="$TEMP_DIR/Vulkan-Headers"

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

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

print_banner() {
    echo "================================================================"
    echo "                Vulkan-Go Auto-Update Script"
    echo "================================================================"
    echo "This script will:"
    echo "  1. Clone/update the official Vulkan-Headers repository"
    echo "  2. Extract the latest Vulkan XML registry"
    echo "  3. Generate updated Go bindings"
    echo "  4. Update version information"
    echo "================================================================"
}

cleanup() {
    if [ -d "$TEMP_DIR" ]; then
        log_info "Cleaning up temporary directory..."
        rm -rf "$TEMP_DIR"
    fi
}

# Set up trap to cleanup on exit
trap cleanup EXIT

check_dependencies() {
    log_info "Checking dependencies..."
    
    local missing_deps=()
    
    if ! command -v git >/dev/null 2>&1; then
        missing_deps+=("git")
    fi
    
    if ! command -v go >/dev/null 2>&1; then
        missing_deps+=("go")
    fi
    
    if [ ${#missing_deps[@]} -ne 0 ]; then
        log_error "Missing required dependencies: ${missing_deps[*]}"
        log_error "Please install the missing dependencies and try again."
        exit 1
    fi
    
    log_success "All dependencies found"
}

clone_or_update_vulkan_headers() {
    log_info "Setting up Vulkan-Headers repository..."
    
    mkdir -p "$TEMP_DIR"
    
    if [ -d "$VULKAN_HEADERS_DIR" ]; then
        log_info "Updating existing Vulkan-Headers repository..."
        cd "$VULKAN_HEADERS_DIR"
        git fetch origin
        git reset --hard origin/main
    else
        log_info "Cloning Vulkan-Headers repository..."
        cd "$TEMP_DIR"
        git clone --depth 1 "$VULKAN_HEADERS_URL"
    fi
    
    cd "$VULKAN_HEADERS_DIR"
    
    # Get the latest commit hash and date for version tracking
    VULKAN_COMMIT_HASH=$(git rev-parse HEAD)
    VULKAN_COMMIT_DATE=$(git show -s --format=%ci HEAD)
    VULKAN_VERSION=$(grep -oP 'VK_HEADER_VERSION\s+\K\d+' registry/vk.xml || echo "unknown")
    
    log_success "Vulkan-Headers updated successfully"
    log_info "Commit: $VULKAN_COMMIT_HASH"
    log_info "Date: $VULKAN_COMMIT_DATE" 
    log_info "Header Version: $VULKAN_VERSION"
}

backup_existing_bindings() {
    log_info "Creating backup of existing bindings..."
    
    local backup_dir="$PROJECT_ROOT/.backup/$(date +%Y%m%d_%H%M%S)"
    
    if [ -d "$PROJECT_ROOT/pkg/vulkan" ]; then
        mkdir -p "$backup_dir"
        cp -r "$PROJECT_ROOT/pkg/vulkan" "$backup_dir/"
        log_success "Backup created at $backup_dir"
    else
        log_info "No existing bindings found, skipping backup"
    fi
}

copy_vulkan_xml() {
    log_info "Copying Vulkan XML registry..."
    
    local src_xml="$VULKAN_HEADERS_DIR/registry/vk.xml"
    local dst_xml="$PROJECT_ROOT/scripts/vk.xml"
    
    if [ ! -f "$src_xml" ]; then
        log_error "Vulkan XML registry not found at $src_xml"
        exit 1
    fi
    
    cp "$src_xml" "$dst_xml"
    log_success "Vulkan XML registry copied"
}

generate_bindings() {
    log_info "Generating Go bindings from Vulkan XML..."
    
    cd "$PROJECT_ROOT"
    
    # Run the Go generator
    if ! go run scripts/generate.go; then
        log_error "Failed to generate Go bindings"
        exit 1
    fi
    
    log_success "Go bindings generated successfully"
}

update_version_info() {
    log_info "Updating version information..."
    
    local version_file="$PROJECT_ROOT/pkg/vulkan/version.go"
    
    cat > "$version_file" << EOF
// Code generated by update.sh. DO NOT EDIT.

package vulkan

import "fmt"

// Version information
const (
	// HeaderVersion is the Vulkan header version
	HeaderVersion = $VULKAN_VERSION
	
	// GeneratedFromCommit is the git commit hash of Vulkan-Headers used for generation
	GeneratedFromCommit = "$VULKAN_COMMIT_HASH"
	
	// GeneratedFromDate is the commit date of Vulkan-Headers used for generation
	GeneratedFromDate = "$VULKAN_COMMIT_DATE"
	
	// GenerationTime is when these bindings were generated
	GenerationTime = "$(date -u +"%Y-%m-%d %H:%M:%S UTC")"
)

// GetVersionInfo returns detailed version information
func GetVersionInfo() string {
	return fmt.Sprintf("Vulkan-Go Bindings\\n"+
		"  Header Version: %d\\n"+
		"  Generated from: %s\\n"+
		"  Generated on: %s\\n"+
		"  Source commit: %s",
		HeaderVersion, GeneratedFromDate, GenerationTime, GeneratedFromCommit)
}

// IsUpToDate checks if the bindings are based on the latest Vulkan headers
// This is a placeholder function - in a real implementation, this would
// check against the latest available version
func IsUpToDate() bool {
	// TODO: Implement version checking against remote repository
	return true
}
EOF

    log_success "Version information updated"
}

format_and_verify() {
    log_info "Formatting and verifying generated code..."
    
    cd "$PROJECT_ROOT"
    
    # Format the generated Go code
    if ! go fmt ./pkg/vulkan/...; then
        log_warning "Failed to format some generated code"
    fi
    
    # Verify the code compiles
    if ! go build ./pkg/vulkan/...; then
        log_error "Generated code does not compile"
        exit 1
    fi
    
    # Run basic tests if they exist
    if [ -d "tests" ]; then
        log_info "Running basic tests..."
        go test ./tests/... || log_warning "Some tests failed"
    fi
    
    log_success "Code formatting and verification complete"
}

update_documentation() {
    log_info "Updating documentation..."
    
    local changelog_file="$PROJECT_ROOT/CHANGELOG.md"
    local today=$(date +"%Y-%m-%d")
    
    # Create changelog entry
    if [ -f "$changelog_file" ]; then
        # Insert new entry at the top of the changelog
        sed -i "1a\\
\\
## [$VULKAN_VERSION] - $today\\
\\
### Updated\\
- Updated to Vulkan Headers commit $VULKAN_COMMIT_HASH\\
- Generated from Vulkan XML registry dated $VULKAN_COMMIT_DATE\\
\\
" "$changelog_file"
    else
        # Create new changelog
        cat > "$changelog_file" << EOF
# Changelog

All notable changes to this project will be documented in this file.

## [$VULKAN_VERSION] - $today

### Updated
- Updated to Vulkan Headers commit $VULKAN_COMMIT_HASH
- Generated from Vulkan XML registry dated $VULKAN_COMMIT_DATE

EOF
    fi
    
    log_success "Documentation updated"
}

run_final_checks() {
    log_info "Running final checks..."
    
    cd "$PROJECT_ROOT"
    
    # Check that all expected files were generated
    local expected_files=(
        "pkg/vulkan/types.go"
        "pkg/vulkan/enums.go" 
        "pkg/vulkan/commands.go"
        "pkg/vulkan/extensions.go"
        "pkg/vulkan/loader.go"
        "pkg/vulkan/version.go"
    )
    
    for file in "${expected_files[@]}"; do
        if [ ! -f "$file" ]; then
            log_error "Expected file $file was not generated"
            exit 1
        fi
    done
    
    log_success "All expected files generated"
    
    # Get some statistics
    local total_lines=$(find pkg/vulkan -name "*.go" -exec wc -l {} + | tail -n1 | awk '{print $1}')
    local total_files=$(find pkg/vulkan -name "*.go" | wc -l)
    
    log_info "Generated $total_files Go files with $total_lines total lines"
}

main() {
    print_banner
    
    # Parse command line arguments
    local force_update=false
    local skip_backup=false
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            -f|--force)
                force_update=true
                shift
                ;;
            --skip-backup)
                skip_backup=true
                shift
                ;;
            -h|--help)
                echo "Usage: $0 [OPTIONS]"
                echo ""
                echo "Options:"
                echo "  -f, --force        Force update even if no changes detected"
                echo "  --skip-backup      Skip creating backup of existing bindings"
                echo "  -h, --help         Show this help message"
                exit 0
                ;;
            *)
                log_error "Unknown option: $1"
                exit 1
                ;;
        esac
    done
    
    check_dependencies
    clone_or_update_vulkan_headers
    
    if [ "$skip_backup" != true ]; then
        backup_existing_bindings
    fi
    
    copy_vulkan_xml
    generate_bindings
    update_version_info
    format_and_verify
    update_documentation
    run_final_checks
    
    log_success "Vulkan-Go bindings updated successfully!"
    log_info "To use the updated bindings, run: go mod tidy"
}

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