# KCL Composition Utilities
# Provides utilities for composing and merging KCL configurations

# Deep merge utility for KCL schemas
# Recursively merges two dictionaries, with right taking precedence
def deep_merge [left: any, right: any] -> any {
    if ($right | describe) == "record" and ($left | describe) == "record" {
        let merged = {}

        # Start with all keys from left
        for key in ($left | columns) {
            $merged = ($merged | insert $key $left.($key))
        }

        # Merge in keys from right, recursively merging records
        for key in ($right | columns) {
            if $key in ($left | columns) {
                if ($left.($key) | describe) == "record" and ($right.($key) | describe) == "record" {
                    $merged = ($merged | insert $key (deep_merge $left.($key) $right.($key)))
                } else {
                    # Right takes precedence for non-record values
                    $merged = ($merged | insert $key $right.($key))
                }
            } else {
                # New key from right
                $merged = ($merged | insert $key $right.($key))
            }
        }

        $merged
    } else {
        # Non-record types: right takes precedence
        $right
    }
}

# Apply template with overrides
# Usage: apply_template base_template overrides
def apply_template [base: any, overrides: any = {}] -> any {
    deep_merge $base $overrides
}

# Compose multiple templates in order
# Later templates override earlier ones
def compose_templates [...templates: any] -> any {
    $templates | reduce {|template, acc|
        deep_merge $acc $template
    }
}

# Apply conditional overrides based on provider
def apply_provider_overrides [
    base: any,
    provider: str,
    overrides: {str: any} = {}
] -> any {
    let provider_specific = if $provider in $overrides {
        $overrides.($provider)
    } else {
        {}
    }

    let common = if "common" in $overrides {
        $overrides.common
    } else {
        {}
    }

    # Apply: base -> common -> provider_specific
    $base | deep_merge $common | deep_merge $provider_specific
}

# Apply environment-specific overrides
def apply_env_overrides [
    base: any,
    environment: str,
    overrides: {str: any} = {}
] -> any {
    let env_specific = if $environment in $overrides {
        $overrides.($environment)
    } else {
        {}
    }

    deep_merge $base $env_specific
}

# Validate required fields are present
def validate_required [config: any, required_fields: list<str>] -> bool {
    let missing = $required_fields | filter {|field|
        not ($field in ($config | columns))
    }

    if ($missing | length) > 0 {
        error make {
            msg: $"Missing required fields: ($missing | str join ', ')"
        }
    }

    true
}

# Create configuration with validation
def create_config [
    base: any,
    overrides: any = {},
    required: list<str> = [],
    provider?: str,
    environment?: str
] -> any {
    mut result = deep_merge $base $overrides

    # Apply provider-specific overrides if provider specified
    if $provider != null {
        $result = apply_provider_overrides $result $provider $overrides
    }

    # Apply environment-specific overrides if environment specified
    if $environment != null {
        $result = apply_env_overrides $result $environment $overrides
    }

    # Validate required fields
    if ($required | length) > 0 {
        validate_required $result $required
    }

    $result
}

# Template composition patterns
schema CompositionPatterns {
    # Layer composition: core -> workspace -> infra
    layer_compose: def [core: any, workspace: any, infra: any] -> any {
        compose_templates $core $workspace $infra
    }

    # Provider-aware composition
    provider_compose: def [
        base: any,
        provider: str,
        provider_configs: {str: any}
    ] -> any {
        apply_provider_overrides $base $provider $provider_configs
    }

    # Template with variants
    variant_compose: def [
        base_template: any,
        variant: str,
        variants: {str: any}
    ] -> any {
        let variant_config = if $variant in $variants {
            $variants.($variant)
        } else {
            error make {msg: $"Unknown variant: ($variant)"}
        }
        deep_merge $base_template $variant_config
    }
}

# Export utilities
composition_utils = CompositionPatterns {}
