# Dynamic Cache Configuration Manager
# Manages cache settings at runtime via persistent JSON config
# Follows Nushell 0.109.0+ guidelines

# Helper: Get runtime config file path
def get-runtime-config-path [] {
    let home = ($env.HOME? | default "~" | path expand)
    $home | path join ".provisioning" "cache" "config" "settings.json"
}

# Helper: Get system defaults path
def get-defaults-config-path [] {
    let provisioning = ($env.PROVISIONING? | default "/usr/local/provisioning")
    $provisioning | path join "config" "config.defaults.toml"
}

# Helper: Load runtime config file
def load-runtime-config [] {
    let config_path = (get-runtime-config-path)

    if ($config_path | path exists) {
        let load_result = (do {
            open $config_path
        } | complete)

        if $load_result.exit_code == 0 {
            return $load_result.stdout
        }
    }

    # Return empty record if not exists
    {}
}

# Helper: Save runtime config file
def save-runtime-config [
    config: record
] {
    let config_path = (get-runtime-config-path)
    let config_dir = ($config_path | path dirname)

    # Ensure directory exists
    if not ($config_dir | path exists) {
        mkdir $config_dir
    }

    # Save with pretty formatting
    do {
        $config | to json --indent 2 | save --force $config_path
    } | complete | ignore
}

# ============================================================================
# PUBLIC API: Configuration Management
# ============================================================================

# Get complete cache configuration (merged: runtime overrides + defaults)
export def get-cache-config [] {
    let defaults = {
        enabled: true,
        max_cache_size: 104857600,  # 100 MB
        ttl: {
            final_config: 300,       # 5 minutes
            nickel_compilation: 1800,   # 30 minutes
            sops_decryption: 900,    # 15 minutes
            provider_config: 600,    # 10 minutes
            platform_config: 600     # 10 minutes
        },
        paths: {
            base: (($env.HOME? | default "~" | path expand) | path join ".provisioning" "cache" "config")
        },
        security: {
            sops_file_permissions: "0600",
            sops_dir_permissions: "0700"
        },
        validation: {
            strict_mtime: true
        },
        metadata: {
            last_modified: (date now | format date "%Y-%m-%dT%H:%M:%SZ"),
            modified_by: "system",
            version: "1.0"
        }
    }

    # Load runtime overrides
    let runtime = (load-runtime-config)

    # Merge: runtime overrides take precedence
    $defaults | merge $runtime
}

# Get specific cache setting (dot notation: "ttl.final_config")
export def cache-config-get [
    setting_path: string    # "enabled", "ttl.final_config", etc.
] {
    let config = (get-cache-config)
    let result = (do {
        eval $"$config | get ($setting_path)"
    } | complete)

    if $result.exit_code == 0 {
        $result.stdout
    } else {
        null
    }
}

# Set cache configuration (persists to runtime config)
export def cache-config-set [
    setting_path: string
    value: any
] {
    let runtime = (load-runtime-config)

    # Build nested structure from dot notation
    mut updated = $runtime

    # Simple update for direct keys
    if not ($setting_path | str contains ".") {
        $updated = ($updated | insert $setting_path $value)
    } else {
        # For nested paths, we need to handle carefully
        # Convert "ttl.final_config" -> insert into ttl section
        let parts = ($setting_path | split row ".")

        if ($parts | length) == 2 {
            let section = ($parts | get 0)
            let key = ($parts | get 1)

            let section_obj = if ($runtime | has -c $section) {
                $runtime | get $section
            } else {
                {}
            }

            let updated_section = ($section_obj | insert $key $value)
            $updated = ($updated | insert $section $updated_section)
        }
    }

    # Add metadata
    $updated = ($updated | insert "metadata" {
        last_modified: (date now | format date "%Y-%m-%dT%H:%M:%SZ"),
        modified_by: "user",
        version: "1.0"
    })

    save-runtime-config $updated
}

# Reset cache configuration (delete runtime overrides)
export def cache-config-reset [
    setting_path?: string = ""    # Optional: reset specific setting
] {
    if ($setting_path | is-empty) {
        # Delete entire runtime config file
        let config_path = (get-runtime-config-path)
        if ($config_path | path exists) {
            do {
                rm -f $config_path
            } | complete | ignore
        }
    } else {
        # Remove specific setting
        let runtime = (load-runtime-config)

        mut updated = $runtime

        # Handle nested paths
        if not ($setting_path | str contains ".") {
            if ($updated | has -c $setting_path) {
                $updated = ($updated | del $setting_path)
            }
        } else {
            let parts = ($setting_path | split row ".")
            if ($parts | length) == 2 {
                let section = ($parts | get 0)
                let key = ($parts | get 1)

                if ($updated | has -c $section) {
                    let section_obj = ($updated | get $section)
                    let updated_section = (if ($section_obj | has -c $key) {
                        $section_obj | del $key
                    } else {
                        $section_obj
                    })
                    $updated = ($updated | insert $section $updated_section)
                }
            }
        }

        save-runtime-config $updated
    }
}

# Show cache configuration in formatted output
export def cache-config-show [
    --format: string = "yaml"    # "yaml", "json", "table"
] {
    let config = (get-cache-config)

    match $format {
        "json" => {
            $config | to json --indent 2 | print
        },
        "table" => {
            $config | print
        },
        _ => {
            $config | to yaml | print
        }
    }
}

# Validate cache configuration
export def cache-config-validate [] {
    let config = (get-cache-config)

    mut errors = []
    mut warnings = []

    # Validate enabled field
    if not ($config | has -c "enabled") {
        $errors = ($errors | append "Missing 'enabled' field")
    }

    # Validate TTL values (should be positive integers)
    if ($config | has -c "ttl") {
        for ttl_key in [
            "final_config"
            "nickel_compilation"
            "sops_decryption"
            "provider_config"
            "platform_config"
        ] {
            let ttl_value = ($config.ttl | get --optional $ttl_key | default 0)
            if ($ttl_value <= 0) {
                $warnings = ($warnings | append $"TTL ($ttl_key) is not positive: ($ttl_value)")
            }
        }
    }

    # Validate max cache size (should be reasonable)
    if ($config | has -c "max_cache_size") {
        let max_size = $config.max_cache_size
        if ($max_size < 1048576) {  # Less than 1 MB
            $warnings = ($warnings | append $"max_cache_size is very small: ($max_size) bytes")
        }
        if ($max_size > 10737418240) {  # More than 10 GB
            $warnings = ($warnings | append $"max_cache_size is very large: ($max_size) bytes")
        }
    }

    {
        valid: (($errors | length) == 0),
        errors: $errors,
        warnings: $warnings
    }
}

# Get cache statistics along with configuration
export def get-cache-status [] {
    use ./core.nu get-cache-stats

    let config = (get-cache-config)
    let stats = (get-cache-stats)

    {
        configuration: $config,
        statistics: $stats,
        enabled: $config.enabled,
        max_size_mb: ($config.max_cache_size / 1048576),
        current_usage_percent: (
            if ($stats.total_size_mb | is-not-empty) {
                ($stats.total_size_mb / ($config.max_cache_size / 1048576) * 100) | math round -p 1
            } else {
                0
            }
        )
    }
}

# Export configuration to portable format
export def cache-config-export [
    --format: string = "json"
] {
    let config = (get-cache-config)

    match $format {
        "json" => {
            $config | to json --indent 2
        },
        "yaml" => {
            $config | to yaml
        },
        "toml" => {
            # Basic TOML conversion (limited)
            $"[cache]
enabled = ($config.enabled)
max_cache_size = ($config.max_cache_size)
"
        },
        _ => {
            $config | to json --indent 2
        }
    }
}

# Import configuration from JSON string
export def cache-config-import [
    json_string: string
] {
    let result = (do {
        $json_string | from json
    } | complete)

    if $result.exit_code == 0 {
        save-runtime-config $result.stdout
    } else {
        error make { msg: "Failed to parse configuration JSON" }
    }
}

# Get configuration defaults (system-wide)
export def get-cache-defaults [] {
    {
        enabled: true,
        max_cache_size: 104857600,  # 100 MB
        ttl: {
            final_config: 300,
            nickel_compilation: 1800,
            sops_decryption: 900,
            provider_config: 600,
            platform_config: 600
        },
        paths: {
            base: (($env.HOME? | default "~" | path expand) | path join ".provisioning" "cache" "config")
        },
        security: {
            sops_file_permissions: "0600",
            sops_dir_permissions: "0700"
        },
        validation: {
            strict_mtime: true
        }
    }
}

# Restore default configuration
export def cache-config-restore-defaults [] {
    let config_path = (get-runtime-config-path)
    if ($config_path | path exists) {
        do {
            rm -f $config_path
        } | complete | ignore
    }
}
