# Cache Manager - Progressive version cache with infra hierarchy
# Handles cache lookup, storage, and hierarchy management

use version_loader.nu load-version-from-source
use grace_checker.nu is-cache-valid?

# Get version with progressive cache hierarchy
export def get-cached-version [
    component: string       # Component name (e.g., kubernetes, containerd)
] {
    # Cache hierarchy: infra -> provisioning -> source

    # 1. Try infra cache first (project-specific)
    let infra_version = (get-infra-cache $component)
    if ($infra_version | is-not-empty) {
        if (is-cache-valid? $component "infra") {
            return $infra_version
        }
    }

    # 2. Try provisioning cache (system-wide)
    let prov_version = (get-provisioning-cache $component)
    if ($prov_version | is-not-empty) {
        if (is-cache-valid? $component "provisioning") {
            return $prov_version
        }
    }

    # 3. Load from source and cache
    print $"⚠️ Loading ($component) from source \(cache miss or expired\)"
    let version = (load-version-from-source $component)

    if ($version | is-not-empty) {
        # Cache in both levels
        cache-version $component $version "provisioning"
        cache-version $component $version "infra"
        return $version
    }

    # 4. Return empty if not found
    ""
}

# Get version from infra cache
def get-infra-cache [component: string] {
    let cache_path = (get-infra-cache-path)
    let cache_file = ($cache_path | path join "versions.json")

    if not ($cache_file | path exists) {
        return ""
    }

    let result = (do { open $cache_file } | complete)
    if $result.exit_code != 0 {
        return ""
    }

    let cache_data = ($result.stdout | from json)
    let version_result = (do { $cache_data | get $component } | complete)
    let version_data = if $version_result.exit_code == 0 { $version_result.stdout } else { {} }
    let current_result = (do { $version_data | get current } | complete)
    if $current_result.exit_code == 0 { $current_result.stdout } else { "" }
}

# Get version from provisioning cache
def get-provisioning-cache [component: string] {
    let cache_path = (get-provisioning-cache-path)
    let cache_file = ($cache_path | path join "versions.json")

    if not ($cache_file | path exists) {
        return ""
    }

    let result = (do { open $cache_file } | complete)
    if $result.exit_code != 0 {
        return ""
    }

    let cache_data = ($result.stdout | from json)
    let version_result = (do { $cache_data | get $component } | complete)
    let version_data = if $version_result.exit_code == 0 { $version_result.stdout } else { {} }
    let current_result = (do { $version_data | get current } | complete)
    if $current_result.exit_code == 0 { $current_result.stdout } else { "" }
}

# Cache version data
export def cache-version [
    component: string       # Component name
    version: string        # Version string
    cache_type: string     # "infra" or "provisioning"
] {
    let cache_path = if $cache_type == "infra" {
        get-infra-cache-path
    } else {
        get-provisioning-cache-path
    }

    let cache_file = ($cache_path | path join "versions.json")

    # Ensure cache directory exists
    mkdir ($cache_file | path dirname)

    # Load existing cache or create new
    let existing_cache = if ($cache_file | path exists) {
        let result = (do { open $cache_file } | complete)
        if $result.exit_code == 0 { $result.stdout | from json } else { {} }
    } else {
        {}
    }

    # Update cache entry
    let updated_cache = ($existing_cache | upsert $component {
        current: $version
        cached_at: (date now | format date '%Y-%m-%dT%H:%M:%SZ')
        cache_type: $cache_type
        grace_period: (get-default-grace-period)
    })

    # Save cache
    $updated_cache | save -f $cache_file
}

# Get cache paths from config
export def get-infra-cache-path [] {
    use ../config/accessor.nu config-get
    let infra_path = (config-get "paths.infra" "")
    let current_infra = (config-get "infra.current" "default")

    if ($infra_path | is-empty) {
        return (get-provisioning-cache-path)
    }

    $infra_path | path join $current_infra "cache"
}

export def get-provisioning-cache-path [] {
    use ../config/accessor.nu config-get
    config-get "cache.path" ".cache/versions"
}

def get-default-grace-period [] {
    use ../config/accessor.nu config-get
    config-get "cache.grace_period" 86400
}

# Initialize cache system
export def init-cache-system [] {
    let infra_cache = (get-infra-cache-path)
    let prov_cache = (get-provisioning-cache-path)

    mkdir $infra_cache
    mkdir $prov_cache

    # Create empty cache files if they don't exist
    let infra_file = ($infra_cache | path join "versions.json")
    let prov_file = ($prov_cache | path join "versions.json")

    if not ($infra_file | path exists) {
        {} | save $infra_file
    }

    if not ($prov_file | path exists) {
        {} | save $prov_file
    }
}

# Clear cache system
export def clear-cache-system [] {
    let infra_cache = (get-infra-cache-path)
    let prov_cache = (get-provisioning-cache-path)

    if ($infra_cache | path exists) {
        do { rm -rf $infra_cache } | complete | ignore
    }
    if ($prov_cache | path exists) {
        do { rm -rf $prov_cache } | complete | ignore
    }

    init-cache-system
}

# Show cache status
export def show-cache-status [] {
    let infra_cache = (get-infra-cache-path | path join "versions.json")
    let prov_cache = (get-provisioning-cache-path | path join "versions.json")

    print "📁 Cache Locations:"
    print $"  Infra:        ($infra_cache)"
    print $"  Provisioning: ($prov_cache)"
    print ""

    if ($infra_cache | path exists) {
        let infra_data = (open $infra_cache)
        let infra_count = ($infra_data | columns | length)
        print $"🏗️  Infra cache: ($infra_count) components"
    } else {
        print "🏗️  Infra cache: not found"
    }

    if ($prov_cache | path exists) {
        let prov_data = (open $prov_cache)
        let prov_count = ($prov_data | columns | length)
        print $"⚙️  Provisioning cache: ($prov_count) components"
    } else {
        print "⚙️  Provisioning cache: not found"
    }
}
