# SecretumVault Plugin Wrapper with HTTP Fallback
# Provides high-level functions for SecretumVault operations with graceful HTTP fallback

# Selective imports (ADR-025 Phase 3 Layer 2).
use lib_provisioning/config/accessor/core.nu [config-get]

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

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

# Get SecretumVault service URL
def get-secretumvault-url [] {
    config-get "kms.secretumvault.server_url" "http://localhost:8200"
}

# Get SecretumVault auth token
def get-secretumvault-token [] {
    let token = (
        if ($env.SECRETUMVAULT_TOKEN? != null) {
            $env.SECRETUMVAULT_TOKEN
        } else {
            ""
        }
    )
    if ($token | is-empty) {
        config-get "kms.secretumvault.auth_token" ""
    } else {
        $token
    }
}

# Get SecretumVault mount point
def get-secretumvault-mount-point [] {
    config-get "kms.secretumvault.mount_point" "transit"
}

# Get default SecretumVault key name
def get-secretumvault-key-name [] {
    config-get "kms.secretumvault.key_name" "provisioning-master"
}

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

# Encrypt data using SecretumVault plugin
export def plugin-secretumvault-encrypt [
    plaintext: string
    --key-id: string = ""  # Encryption key ID
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }

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

            secretumvault ...$args
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin SecretumVault encrypt failed, falling back to HTTP"
    }

    # HTTP fallback - call SecretumVault service directly
    print "⚠️ nu_plugin_secretumvault not available - using HTTP fallback for secrets"

    let sv_url = (get-secretumvault-url)
    let sv_token = (get-secretumvault-token)
    let mount_point = (get-secretumvault-mount-point)
    let url = $"($sv_url)/v1/($mount_point)/encrypt/($key_name)"

    if ($sv_token | is-empty) {
        error make {
            msg: "SecretumVault authentication failed"
            label: {
                text: "SECRETUMVAULT_TOKEN not set"
                span: (metadata $plaintext).span
            }
        }
    }

    let result = (do -i {
        let plaintext_b64 = ($plaintext | encode base64)
        let body = {plaintext: $plaintext_b64}

        http post -H ["X-Vault-Token" $sv_token] $url $body
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "SecretumVault encryption failed"
        label: {
            text: $"Failed to encrypt data with key ($key_name)"
            span: (metadata $plaintext).span
        }
    }
}

# Decrypt data using SecretumVault plugin
export def plugin-secretumvault-decrypt [
    ciphertext: string
    --key-id: string = ""  # Encryption key ID
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }

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

            secretumvault ...$args
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin SecretumVault decrypt failed, falling back to HTTP"
    }

    # HTTP fallback - call SecretumVault service directly
    print "⚠️ nu_plugin_secretumvault not available - using HTTP fallback for secrets"

    let sv_url = (get-secretumvault-url)
    let sv_token = (get-secretumvault-token)
    let mount_point = (get-secretumvault-mount-point)
    let url = $"($sv_url)/v1/($mount_point)/decrypt/($key_name)"

    if ($sv_token | is-empty) {
        error make {
            msg: "SecretumVault authentication failed"
            label: {
                text: "SECRETUMVAULT_TOKEN not set"
                span: (metadata $ciphertext).span
            }
        }
    }

    let result = (do -i {
        let body = {ciphertext: $ciphertext}

        let response = (http post -H ["X-Vault-Token" $sv_token] $url $body)

        if ($response.data.plaintext? != null) {
            {
                plaintext: ($response.data.plaintext | decode base64),
                key_id: ($response.data.key_id? // $key_name)
            }
        } else {
            $response
        }
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "SecretumVault decryption failed"
        label: {
            text: $"Failed to decrypt data with key ($key_name)"
            span: (metadata $ciphertext).span
        }
    }
}

# Generate data key using SecretumVault plugin
export def plugin-secretumvault-generate-key [
    --bits: int = 256     # Key size in bits (128, 256, 2048, 4096)
    --key-id: string = "" # Encryption key ID
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }

    if $enabled and $available {
        let plugin_result = (try-plugin {
            let args = if ($key_id | is-empty) {
                [generate-key --bits $bits]
            } else {
                [generate-key --bits $bits --key-id $key_id]
            }

            secretumvault ...$args
        })

        if $plugin_result != null {
            return $plugin_result
        }

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

    # HTTP fallback
    print "⚠️ nu_plugin_secretumvault not available - using HTTP fallback for secrets"

    let sv_url = (get-secretumvault-url)
    let sv_token = (get-secretumvault-token)
    let mount_point = (get-secretumvault-mount-point)
    let url = $"($sv_url)/v1/($mount_point)/datakey/plaintext/($key_name)"

    if ($sv_token | is-empty) {
        error make {
            msg: "SecretumVault authentication failed"
            label: {
                text: "SECRETUMVAULT_TOKEN not set"
            }
        }
    }

    let result = (do -i {
        let body = {bits: $bits}
        http post -H ["X-Vault-Token" $sv_token] $url $body
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "SecretumVault key generation failed"
        label: {
            text: $"Failed to generate key with ($bits) bits"
        }
    }
}

# Check SecretumVault health using plugin
export def plugin-secretumvault-health [] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available

    if $enabled and $available {
        let plugin_result = (try-plugin {
            secretumvault health
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin SecretumVault health check failed, falling back to HTTP"
    }

    # HTTP fallback
    print "⚠️ nu_plugin_secretumvault not available - using HTTP fallback for secrets"

    let sv_url = (get-secretumvault-url)
    let url = $"($sv_url)/v1/sys/health"

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

    if $result != null {
        return $result
    }

    {
        healthy: false
        status: "unavailable"
        message: "SecretumVault service unreachable"
    }
}

# Get SecretumVault version using plugin
export def plugin-secretumvault-version [] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available

    if $enabled and $available {
        let plugin_result = (try-plugin {
            secretumvault version
        })

        if $plugin_result != null {
            return $plugin_result
        }

        print "⚠️ Plugin SecretumVault version failed, falling back to HTTP"
    }

    # HTTP fallback
    print "⚠️ nu_plugin_secretumvault not available - using HTTP fallback for secrets"

    let sv_url = (get-secretumvault-url)
    let url = $"($sv_url)/v1/sys/health"

    let result = (do -i {
        let response = (http get $url)
        $response.version? // "unknown"
    })

    if $result != null {
        return $result
    }

    "unavailable"
}

# Rotate encryption key using plugin
export def plugin-secretumvault-rotate-key [
    --key-id: string = ""  # Key ID to rotate
] {
    let enabled = is-plugin-enabled
    let available = is-plugin-available
    let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }

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

            secretumvault ...$args
        })

        if $plugin_result != null {
            return $plugin_result
        }

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

    # HTTP fallback
    print "⚠️ nu_plugin_secretumvault not available - using HTTP fallback for secrets"

    let sv_url = (get-secretumvault-url)
    let sv_token = (get-secretumvault-token)
    let mount_point = (get-secretumvault-mount-point)
    let url = $"($sv_url)/v1/($mount_point)/keys/($key_name)/rotate"

    if ($sv_token | is-empty) {
        error make {
            msg: "SecretumVault authentication failed"
            label: {
                text: "SECRETUMVAULT_TOKEN not set"
                span: (metadata $key_name).span
            }
        }
    }

    let result = (do -i {
        http post -H ["X-Vault-Token" $sv_token] $url
    })

    if $result != null {
        return $result
    }

    error make {
        msg: "SecretumVault key rotation failed"
        label: {
            text: $"Failed to rotate key ($key_name)"
            span: (metadata $key_name).span
        }
    }
}

# Get SecretumVault plugin status and configuration
export def plugin-secretumvault-info [] {
    let plugin_available = is-plugin-available
    let plugin_enabled = is-plugin-enabled
    let sv_url = get-secretumvault-url
    let mount_point = get-secretumvault-mount-point
    let key_name = get-secretumvault-key-name
    let has_token = (not (get-secretumvault-token | is-empty))

    {
        plugin_available: $plugin_available
        plugin_enabled: $plugin_enabled
        service_url: $sv_url
        mount_point: $mount_point
        default_key: $key_name
        authenticated: $has_token
        mode: (if ($plugin_enabled and $plugin_available) { "plugin (native)" } else { "http fallback" })
    }
}

# Encrypt configuration file using SecretumVault
export def encrypt-config-file [
    config_file: string
    --output: string = ""     # Output file path (default: <file>.enc)
    --key-id: string = ""     # Encryption key ID
] {
    let out_file = if ($output | is-empty) {
        $"($config_file).enc"
    } else {
        $output
    }

    let result = (do -i {
        let content = (open $config_file --raw)
        let encrypted = (plugin-secretumvault-encrypt $content --key-id $key_id)

        # Save encrypted content
        if ($encrypted | type) == "record" {
            $encrypted.ciphertext | save --force $out_file
        } else {
            $encrypted | save --force $out_file
        }

        print $"✅ Configuration encrypted to: ($out_file)"
        {
            success: true
            input_file: $config_file
            output_file: $out_file
            key_id: (if ($key_id | is-empty) { (get-secretumvault-key-name) } else { $key_id })
        }
    })

    if $result == null {
        error make {
            msg: "Failed to encrypt configuration file"
            label: {
                text: "Check file permissions and SecretumVault service"
                span: (metadata $config_file).span
            }
        }
    }

    $result
}

# Decrypt configuration file using SecretumVault
export def decrypt-config-file [
    encrypted_file: string
    --output: string = ""     # Output file path (default: <file>.dec)
    --key-id: string = ""     # Encryption key ID
] {
    let out_file = if ($output | is-empty) {
        let base_name = ($encrypted_file | str replace '.enc' '')
        $"($base_name).dec"
    } else {
        $output
    }

    let result = (do -i {
        let encrypted_content = (open $encrypted_file --raw)
        let decrypted = (plugin-secretumvault-decrypt $encrypted_content --key-id $key_id)

        # Save decrypted content
        if ($decrypted | type) == "record" {
            if ($decrypted.plaintext? != null) {
                $decrypted.plaintext | save --force $out_file
            } else {
                $decrypted | to json | save --force $out_file
            }
        } else {
            $decrypted | save --force $out_file
        }

        print $"✅ Configuration decrypted to: ($out_file)"
        {
            success: true
            input_file: $encrypted_file
            output_file: $out_file
            key_id: (if ($key_id | is-empty) { (get-secretumvault-key-name) } else { $key_id })
        }
    })

    if $result == null {
        error make {
            msg: "Failed to decrypt configuration file"
            label: {
                text: "Check file permissions and SecretumVault service"
                span: (metadata $encrypted_file).span
            }
        }
    }

    $result
}
