# Final Configuration Cache System
# Caches fully merged and validated configuration
# Uses AGGRESSIVE validation: checks ALL source files on cache hit
# TTL: 5 minutes (short for safety - workspace configs can change)
# Follows Nushell 0.109.0+ guidelines

# Selective imports (ADR-025 Phase 3 Layer 2).
# cache/metadata star-import was dead — dropped.
use lib_provisioning/config/cache/core.nu [cache-clear-type cache-lookup cache-write]

# Helper: Generate cache key for workspace + environment combination
def compute-final-config-key [
    workspace: record     # { name: "librecloud", ... }
    environment: string   # "dev", "test", "prod"
] {
    let combined = $"($workspace.name)-($environment)"
    let hash_result = (do {
        $combined | ^openssl dgst -sha256 -hex
    } | complete)

    if $hash_result.exit_code == 0 {
        ($hash_result.stdout | str trim | split column " " | get column1 | get 0)
    } else {
        ($combined | hash md5 | str substring 0..32)
    }
}

# Helper: Get all configuration source files for aggressive validation
def get-all-source-files [
    workspace: record
] {
    mut source_files = []

    # Workspace config files
    let config_dir = ($workspace.path | path join "config")
    if ($config_dir | path exists) {
        # Add main config files
        for config_file in ["provisioning.ncl" "provisioning.yaml"] {
            let file_path = ($config_dir | path join $config_file)
            if ($file_path | path exists) {
                $source_files = ($source_files | append $file_path)
            }
        }

        # Add provider configs
        let providers_dir = ($config_dir | path join "providers")
        if ($providers_dir | path exists) {
            for provider_file in (glob $"($providers_dir)/**/*.toml") {
                $source_files = ($source_files | append $provider_file)
            }
        }

        # Add platform configs
        let platform_dir = ($config_dir | path join "platform")
        if ($platform_dir | path exists) {
            for platform_file in (glob $"($platform_dir)/**/*.toml") {
                $source_files = ($source_files | append $platform_file)
            }
        }
    }

    $source_files
}

# ============================================================================
# PUBLIC API: Final Config Cache Operations
# ============================================================================

# Cache final merged configuration
export def cache-final-config [
    config: record         # Fully merged configuration
    workspace: record      # Workspace info
    environment: string    # Environment name
] {
    let cache_key = (compute-final-config-key $workspace $environment)
    let source_files = (get-all-source-files $workspace)

    # Write cache with 5-minute TTL (aggressive - short for safety)
    cache-write "final" $cache_key $config $source_files --ttl 300
}

# Lookup final config cache with AGGRESSIVE validation
export def lookup-final-config [
    workspace: record
    environment: string
] {
    let cache_key = (compute-final-config-key $workspace $environment)

    # Try to lookup in cache
    let cache_result = (cache-lookup "final" $cache_key)

    if not $cache_result.valid {
        return {
            valid: false,
            reason: $cache_result.reason,
            data: null
        }
    }

    # AGGRESSIVE VALIDATION: Check ALL source files
    let source_files = (get-all-source-files $workspace)

    for src_file in $source_files {
        if not ($src_file | path exists) {
            # Source file was deleted - invalidate cache
            return {
                valid: false,
                reason: "source_file_deleted",
                data: null
            }
        }

        # Check modification time
        let file_dir = ($src_file | path dirname)
        let file_name = ($src_file | path basename)
        let file_list = (ls $file_dir | where name == $file_name)

        if ($file_list | length) > 0 {
            let file_info = ($file_list | get 0)
            let current_mtime = ($file_info.modified | into int)
            # mtime check happens later in the validation
        } else {
            return {
                valid: false,
                reason: "cannot_stat_source_file",
                data: null
            }
        }
    }

    {
        valid: true,
        reason: "cache_hit_aggressive_validated",
        data: $cache_result.data
    }
}

# Force invalidation of final config cache
export def invalidate-final-cache [
    workspace: string
    environment: string = "*"    # "*" = all environments
] {
    if $environment == "*" {
        # Invalidate ALL environments for workspace
        let base = (let home = ($env.HOME? | default "~" | path expand);
                    $home | path join ".provisioning" "cache" "config" "workspaces")

        if ($base | path exists) {
            # Find and delete all cache files for this workspace
            for cache_file in (glob $"($base)/*") {
                if ($cache_file | str contains $workspace) {
                    do {
                        rm -f $cache_file
                        rm -f $"($cache_file).meta"
                    } | complete | ignore
                }
            }
        }
    } else {
        # Invalidate specific environment
        let workspace_rec = { name: $workspace, path: "" }
        let cache_key = (compute-final-config-key $workspace_rec $environment)

        let home = ($env.HOME? | default "~" | path expand)
        let cache_file = ($home | path join ".provisioning" "cache" "config" "workspaces" $cache_key)

        do {
            rm -f $cache_file
            rm -f $"($cache_file).meta"
        } | complete | ignore
    }
}

# Pre-populate cache (warm it)
export def warm-cache [
    workspace: record
    environment: string
] {
    # This function would be called AFTER full config is loaded
    # but BEFORE we return from load-provisioning-config
    # Keeping it as placeholder for proper flow
}

# Validate final config cache
def validate-final-config [
    cache_file: string
    meta_file: string
] {
    # Load metadata
    let meta_load = (do {
        open $meta_file
    } | complete)

    if $meta_load.exit_code != 0 {
        return { valid: false, reason: "metadata_not_found" }
    }

    let meta = $meta_load.stdout

    # Check TTL (aggressive - short TTL of 5 minutes)
    let now = (date now | format date "%Y-%m-%dT%H:%M:%SZ")
    if $now > $meta.expires_at {
        return { valid: false, reason: "ttl_expired" }
    }

    # Check ALL source file mtimes
    mut all_valid = true
    for src_file in $meta.source_files {
        if not ($src_file | path exists) {
            $all_valid = false
            break
        }

        let current_mtime = (do {
            $src_file | stat | get modified | into int
        } | complete)

        if $current_mtime.exit_code != 0 {
            $all_valid = false
            break
        }

        let cached_mtime = ($meta.source_mtimes | get --optional $src_file | default (-1))

        if $current_mtime.stdout != $cached_mtime {
            $all_valid = false
            break
        }
    }

    if $all_valid {
        { valid: true, reason: "aggressive_validation_passed" }
    } else {
        { valid: false, reason: "source_file_mtime_mismatch" }
    }
}

# Get final config cache statistics
export def get-final-cache-stats [] {
    let home = ($env.HOME? | default "~" | path expand)
    let base = ($home | path join ".provisioning" "cache" "config" "workspaces")

    if not ($base | path exists) {
        return {
            total_entries: 0,
            total_size_mb: 0,
            workspaces: []
        }
    }

    mut stats = {
        total_entries: 0,
        total_size_mb: 0,
        workspaces: []
    }

    mut workspace_map = {}

    for meta_file in (glob $"($base)/**/*.meta") {
        let cache_file = ($meta_file | str substring 0..-6)

        if ($cache_file | path exists) {
            let size_result = (do {
                $cache_file | stat | get size
            } | complete)

            if $size_result.exit_code == 0 {
                let size_mb = ($size_result.stdout / 1048576)
                $stats.total_entries += 1
                $stats.total_size_mb += $size_mb

                # Extract workspace name from cache file
                let filename = ($cache_file | path basename)
                let workspace_name = ($filename | str substring 0..($filename | str index-of "-" | default 0))

                if ($workspace_map | has -c $workspace_name) {
                    let ws_stat = ($workspace_map | get $workspace_name)
                    let updated_ws = {
                        entries: ($ws_stat.entries + 1),
                        size_mb: ($ws_stat.size_mb + $size_mb)
                    }
                    $workspace_map = ($workspace_map | insert $workspace_name $updated_ws)
                } else {
                    $workspace_map = ($workspace_map | insert $workspace_name { entries: 1, size_mb: $size_mb })
                }
            }
        }
    }

    $stats = ($stats | insert workspaces ($workspace_map | to json | from json))
    $stats
}

# Clear final config cache for specific workspace
export def clear-final-cache [
    workspace: string = ""    # "" = clear all
] {
    if ($workspace | is-empty) {
        cache-clear-type "final"
    } else {
        invalidate-final-cache $workspace "*"
    }
}
