#!/bin/bash
set -eo pipefail

# generate-models.sh - Generate Rust models from Flux CRDs using kopium
#
# Runs kopium on all CRD files to generate Rust structs.
# Output goes to src/models/_generated/ (gitignored).

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
CRDS_DIR="$PROJECT_ROOT/crds"
GENERATED_DIR="$PROJECT_ROOT/src/models/_generated"

# Check if kopium is installed
if ! command -v kopium &> /dev/null; then
    echo "Error: kopium is not installed" >&2
    echo "" >&2
    echo "Install it with:" >&2
    echo "  cargo install kopium" >&2
    exit 1
fi

# Ensure generated directory exists
mkdir -p "$GENERATED_DIR"

# Clean previous generated files
echo "Cleaning previous generated models..."
rm -rf "${GENERATED_DIR}"/*.rs

# Check if CRD files exist
if ! ls "${CRDS_DIR}"/*.crds.yaml 1> /dev/null 2>&1; then
    echo "Error: No CRD files found in ${CRDS_DIR}" >&2
    echo "Run scripts/fetch-crds.sh first" >&2
    exit 1
fi

echo "Generating Rust models from CRDs..."
echo ""

# Function to split YAML and process each document
process_crd_file() {
    local crd_file="$1"
    local output_file="$2"
    local temp_dir=$(mktemp -d)
    local docnum=0
    
    # Split multi-document YAML files
    awk -v temp_dir="$temp_dir" '
        BEGIN { docnum = 0 }
        /^---/ {
            if (doc != "") {
                filename = temp_dir "/doc" (++docnum) ".yaml"
                print doc > filename
                close(filename)
                doc = ""
            }
            next
        }
        { doc = doc $0 "\n" }
        END {
            if (doc != "") {
                filename = temp_dir "/doc" (++docnum) ".yaml"
                print doc > filename
                close(filename)
            }
        }
    ' "$crd_file"
    
    # Process each split document
    local combined_output="${temp_dir}/combined.rs"
    > "$combined_output"
    
    local processed=0
    for split_file in "${temp_dir}"/doc*.yaml; do
        [ -f "$split_file" ] || continue
        
        # Process with kopium
        # Use --smart-derive-elision to automatically remove Default from structs that can't derive it
        if kopium --filename "$split_file" --derive Default --derive PartialEq --docs --smart-derive-elision >> "$combined_output" 2>&1; then
            processed=$((processed + 1))
            # Add separator between CRDs if not first
            if [ $processed -gt 1 ]; then
                echo "" >> "$combined_output"
                echo "// ---" >> "$combined_output"
                echo "" >> "$combined_output"
            fi
        else
            echo "Warning: Failed to process one CRD document from $(basename "$crd_file")" >&2
        fi
    done
    
    # Check if we got any output
    if [ $processed -eq 0 ] || [ ! -s "$combined_output" ]; then
        echo "Error: No models generated from ${crd_file}" >&2
        rm -rf "$temp_dir"
        return 1
    fi
    
    # Post-process to remove duplicate prelude modules (keep only the first one)
    # Also ensure BTreeMap and Condition are imported if not already present
    local processed_output="${temp_dir}/processed.rs"
    awk '
        /^mod prelude \{/ {
            if (prelude_seen) {
                skip_prelude = 1
                next
            }
            prelude_seen = 1
            print
            in_prelude = 1
            has_btreemap = 0
            has_condition = 0
            next
        }
        in_prelude && /BTreeMap/ {
            has_btreemap = 1
        }
        in_prelude && /Condition/ {
            has_condition = 1
        }
        in_prelude && /^\}$/ {
            if (!has_btreemap) {
                print "    pub use std::collections::BTreeMap;"
            }
            if (!has_condition) {
                print "    pub use k8s_openapi::apimachinery::pkg::apis::meta::v1::Condition;"
            }
            in_prelude = 0
        }
        /^\}$/ && skip_prelude {
            skip_prelude = 0
            next
        }
        !skip_prelude { print }
    ' "$combined_output" > "$processed_output"
    
    # Write final output with header
    {
        echo "//! Auto-generated models for $(basename "$crd_file" .crds.yaml)"
        echo "//! Generated from: $(basename "$crd_file")"
        echo "//! DO NOT EDIT - This file is auto-generated by kopium"
        echo "#![allow(clippy::all)]"
        echo ""
        cat "$processed_output"
    } > "$output_file"
    
    rm -rf "$temp_dir"
    return 0
}

# Generate models for each CRD file
for crd_file in "${CRDS_DIR}"/*.crds.yaml; do
    filename=$(basename "$crd_file" .crds.yaml)
    # Convert hyphens to underscores for Rust module naming
    module_name=$(echo "$filename" | tr '-' '_')
    output_file="${GENERATED_DIR}/${module_name}.rs"
    
    echo "  → Processing $(basename "$crd_file")"
    
    if ! process_crd_file "$crd_file" "$output_file"; then
        exit 1
    fi
done

echo ""
echo "✓ Successfully generated models in ${GENERATED_DIR}"

# Create mod.rs to export all generated modules
cat > "${GENERATED_DIR}/mod.rs" <<'EOF'
//! Auto-generated Flux CRD models
//! 
//! This module contains Rust structs generated from Flux CRD definitions.
//! All files in this directory are auto-generated and should not be edited manually.

EOF

for crd_file in "${CRDS_DIR}"/*.crds.yaml; do
    filename=$(basename "$crd_file" .crds.yaml)
    # Convert hyphens to underscores to match Rust module naming
    module_name=$(echo "$filename" | tr '-' '_')
    echo "pub mod ${module_name};" >> "${GENERATED_DIR}/mod.rs"
done

echo "✓ Created mod.rs for generated modules"

