# KMS Plugin Wrapper with HTTP Fallback
# Provides graceful degradation to HTTP/CLI when nu_plugin_kms is unavailable

use ../config/accessor.nu *

# Check if KMS plugin is available (registered with Nushell)
def is-plugin-available [] {
    let installed = (version | get installed_plugins)
    $installed | str contains "kms"
}

# Check if KMS plugin is enabled in config
def is-plugin-enabled [] {
    config-get "plugins.kms_enabled" true
}

# Get KMS service base URL
def get-kms-url [] {
    config-get "platform.kms_service.url" "http://localhost:8090"
}

# Get default KMS backend
def get-default-backend [] {
    config-get "security.kms.backend" "rustyvault"
}

# Helper to safely execute a closure and return null on error
def try-plugin [callback: closure] {
    do -i $callback
}

# Encrypt data using KMS
export def plugin-kms-encrypt [
    data: string
    --backend: string = ""  # rustyvault, age, vault, cosmian, aws-kms
    --context: string = ""  # Additional authenticated data
    --key-id: string = ""   # Specific key ID
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let backend_name = if ($backend | is-empty) { get-default-backend } else { $backend }

    if $enabled and $available {
        let plugin_result = (try-plugin {
            let args = if ($context | is-empty) and ($key_id | is-empty) {
                [encrypt $data --backend $backend_name]
            } else if ($context | is-empty) {
                [encrypt $data --backend $backend_name --key-id $key_id]
            } else if ($key_id | is-empty) {
                [encrypt $data --backend $backend_name --context $context]
            } else {
                [encrypt $data --backend $backend_name --context $context --key-id $key_id]
            }

            kms ...$args
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin KMS encrypt failed, falling back to HTTP/CLI"
    }

    # HTTP fallback - call KMS service directly
    print "⚠️ nu_plugin_kms not available - using HTTP fallback for key management"

    let kms_url = (get-kms-url)
    let url = $"($kms_url)/api/encrypt"

    let result = (do -i {
        let body = {data: $data, backend: $backend_name}
        http post $url $body
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "KMS encryption failed"
        label: {
            text: $"Failed to encrypt data with backend ($backend_name)"
            span: (metadata $data).span
        }
    }
}

# Decrypt data using KMS
export def plugin-kms-decrypt [
    ciphertext: string
    --backend: string = ""  # rustyvault, age, vault, cosmian, aws-kms
    --context: string = ""  # Additional authenticated data
    --key-id: string = ""   # Specific key ID
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let backend_name = if ($backend | is-empty) { get-default-backend } else { $backend }

    if $enabled and $available {
        let plugin_result = (try-plugin {
            let args = if ($context | is-empty) and ($key_id | is-empty) {
                [decrypt $ciphertext --backend $backend_name]
            } else if ($context | is-empty) {
                [decrypt $ciphertext --backend $backend_name --key-id $key_id]
            } else if ($key_id | is-empty) {
                [decrypt $ciphertext --backend $backend_name --context $context]
            } else {
                [decrypt $ciphertext --backend $backend_name --context $context --key-id $key_id]
            }

            kms ...$args
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin KMS decrypt failed, falling back to HTTP/CLI"
    }

    # HTTP fallback - call KMS service directly
    print "⚠️ nu_plugin_kms not available - using HTTP fallback for key management"

    let kms_url = (get-kms-url)
    let url = $"($kms_url)/api/decrypt"

    let result = (do -i {
        let body = {ciphertext: $ciphertext, backend: $backend_name}
        http post $url $body
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "KMS decryption failed"
        label: {
            text: $"Failed to decrypt data with backend ($backend_name)"
            span: (metadata $ciphertext).span
        }
    }
}

# Generate new encryption key
export def plugin-kms-generate-key [
    --backend: string = ""  # rustyvault, age, vault, cosmian, aws-kms
    --key-type: string = "aes256"  # aes256, rsa2048, rsa4096, ed25519
    --name: string = ""     # Key name/alias
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let backend_name = if ($backend | is-empty) { get-default-backend } else { $backend }

    if $enabled and $available {
        let plugin_result = (try-plugin {
            let args = if ($name | is-empty) {
                [generate-key --backend $backend_name --key-type $key_type]
            } else {
                [generate-key --backend $backend_name --key-type $key_type --name $name]
            }

            kms ...$args
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin KMS generate-key failed, falling back to HTTP"
    }

    # HTTP fallback
    print "⚠️ nu_plugin_kms not available - using HTTP fallback for key management"

    let kms_url = (get-kms-url)
    let url = $"($kms_url)/api/keys/generate"

    let body = if ($name | is-empty) {
        {backend: $backend_name, key_type: $key_type}
    } else {
        {backend: $backend_name, key_type: $key_type, name: $name}
    }

    let result = (do -i {
        http post $url $body
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "KMS key generation failed"
        label: {
            text: $"Failed to generate key with backend ($backend_name)"
        }
    }
}

# Get KMS service status
export def plugin-kms-status [] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available

    if $enabled and $available {
        let plugin_result = (try-plugin {
            kms status
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin KMS status failed, falling back to HTTP"
    }

    # HTTP fallback
    print "⚠️ nu_plugin_kms not available - using HTTP fallback for key management"

    let kms_url = (get-kms-url)
    let url = $"($kms_url)/health"

    let result = (do -i {
        http get $url
    })

    if $result != null {
        return $result
    }

    {
        status: "unavailable"
        message: "KMS service unreachable"
    }
}

# List available KMS backends
export def plugin-kms-backends [] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available

    if $enabled and $available {
        let plugin_result = (try-plugin {
            kms backends
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin KMS backends failed, falling back to HTTP"
    }

    # HTTP fallback
    print "⚠️ nu_plugin_kms not available - using HTTP fallback for key management"

    let kms_url = (get-kms-url)
    let url = $"($kms_url)/api/backends"

    let result = (do -i {
        let response = (http get $url)
        $response.backends? | default []
    })

    if $result != null {
        return $result
    }

    # Return known backends as fallback
    [
        {name: "rustyvault", available: true, description: "RustyVault KMS (primary)"}
        {name: "age", available: true, description: "Age encryption"}
        {name: "vault", available: false, description: "HashiCorp Vault"}
        {name: "cosmian", available: false, description: "Cosmian KMS"}
        {name: "aws-kms", available: false, description: "AWS Key Management Service"}
    ]
}

# Rotate encryption key
export def plugin-kms-rotate-key [
    key_id: string
    --backend: string = ""  # rustyvault, age, vault, cosmian, aws-kms
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let backend_name = if ($backend | is-empty) { get-default-backend } else { $backend }

    if $enabled and $available {
        let plugin_result = (try-plugin {
            kms rotate-key $key_id --backend $backend_name
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin KMS rotate-key failed, falling back to HTTP"
    }

    # HTTP fallback
    print "⚠️ nu_plugin_kms not available - using HTTP fallback for key management"

    let kms_url = (get-kms-url)
    let url = $"($kms_url)/api/keys/rotate"

    let result = (do -i {
        http post $url {backend: $backend_name, key_id: $key_id}
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "KMS key rotation failed"
        label: {
            text: $"Failed to rotate key ($key_id) with backend ($backend_name)"
            span: (metadata $key_id).span
        }
    }
}

# List encryption keys
export def plugin-kms-list-keys [
    --backend: string = ""  # rustyvault, age, vault, cosmian, aws-kms
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let backend_name = if ($backend | is-empty) { get-default-backend } else { $backend }

    if $enabled and $available {
        let plugin_result = (try-plugin {
            kms list-keys --backend $backend_name
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin KMS list-keys failed, falling back to HTTP"
    }

    # HTTP fallback
    print "⚠️ nu_plugin_kms not available - using HTTP fallback for key management"

    let kms_url = (get-kms-url)
    let url = $"($kms_url)/api/keys?backend=($backend_name)"

    let result = (do -i {
        let response = (http get $url)
        $response.keys? | default []
    })

    if $result != null {
        return $result
    }

    []
}

# Get KMS plugin status and configuration
export def plugin-kms-info [] {
    let plugin_available = is-plugin-available
    let plugin_enabled = is-plugin-enabled
    let default_backend = get-default-backend
    let kms_url = get-kms-url

    {
        plugin_available: $plugin_available
        plugin_enabled: $plugin_enabled
        default_backend: $default_backend
        kms_service_url: $kms_url
        mode: (if ($plugin_enabled and $plugin_available) { "plugin" } else { "http" })
    }
}
