#!/usr/bin/env nu

# VAPORA Configuration Backup Script
# Backs up Kubernetes ConfigMaps, Secrets, and deployment configs
# Follows NUSHELL_GUIDELINES.md - 17 rules

# Get current timestamp
def get-timestamp []: string {
    date now | format date "%Y%m%d-%H%M%S"
}

# Get Kubernetes namespace from environment or use default
def get-namespace []: string {
    if ("VAPORA_NAMESPACE" in $env) {
        $env.VAPORA_NAMESPACE
    } else {
        "vapora"
    }
}

# Backup ConfigMaps
def backup-configmaps [
    output_dir: string
    namespace: string
]: record {
    print $"Backing up ConfigMaps from namespace [$namespace]..."

    let output_file = $"($output_dir)/configmaps-$(get-timestamp).yaml"
    let result = do {
        ^kubectl get configmaps \
            -n $namespace \
            -o yaml \
            > $output_file \
            2>&1
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true,
            file: $output_file,
            count: (
                do {
                    ^kubectl get configmaps -n $namespace --no-headers 2>/dev/null
                } | complete | if ($in.exit_code == 0) {
                    ($in.stdout | lines | length)
                } else {
                    0
                }
            ),
            error: null
        }
    } else {
        {
            success: false,
            file: $output_file,
            count: 0,
            error: ($result.stderr | str trim)
        }
    }
}

# Backup Secrets
def backup-secrets [
    output_dir: string
    namespace: string
]: record {
    print $"Backing up Secrets from namespace [$namespace]..."

    let output_file = $"($output_dir)/secrets-$(get-timestamp).yaml"
    let result = do {
        ^kubectl get secrets \
            -n $namespace \
            -o yaml \
            > $output_file \
            2>&1
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true,
            file: $output_file,
            count: (
                do {
                    ^kubectl get secrets -n $namespace --no-headers 2>/dev/null
                } | complete | if ($in.exit_code == 0) {
                    ($in.stdout | lines | length)
                } else {
                    0
                }
            ),
            error: null
        }
    } else {
        {
            success: false,
            file: $output_file,
            count: 0,
            error: ($result.stderr | str trim)
        }
    }
}

# Backup Deployment manifests
def backup-deployments [
    output_dir: string
    namespace: string
]: record {
    print $"Backing up Deployments from namespace [$namespace]..."

    let output_file = $"($output_dir)/deployments-$(get-timestamp).yaml"
    let result = do {
        ^kubectl get deployments,statefulsets,daemonsets \
            -n $namespace \
            -o yaml \
            > $output_file \
            2>&1
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true,
            file: $output_file,
            resource_types: ["deployments", "statefulsets", "daemonsets"],
            error: null
        }
    } else {
        {
            success: false,
            file: $output_file,
            resource_types: [],
            error: ($result.stderr | str trim)
        }
    }
}

# Backup Services and Ingress
def backup-networking [
    output_dir: string
    namespace: string
]: record {
    print $"Backing up Services and Ingress from namespace [$namespace]..."

    let output_file = $"($output_dir)/networking-$(get-timestamp).yaml"
    let result = do {
        ^kubectl get services,ingresses \
            -n $namespace \
            -o yaml \
            > $output_file \
            2>&1
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true,
            file: $output_file,
            resource_types: ["services", "ingresses"],
            error: null
        }
    } else {
        {
            success: false,
            file: $output_file,
            resource_types: [],
            error: ($result.stderr | str trim)
        }
    }
}

# Compress all backup files
def compress-backups [output_dir: string]: record {
    print $"Compressing backup files..."

    let archive_name = $"configs-$(get-timestamp).tar.gz"
    let result = do {
        ^tar -czf $archive_name -C $output_dir . 2>&1
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true,
            archive: $archive_name,
            size: (
                do {
                    ^ls -lh $archive_name 2>/dev/null
                } | complete | if ($in.exit_code == 0) {
                    ($in.stdout | str trim)
                } else {
                    "unknown"
                }
            ),
            error: null
        }
    } else {
        {
            success: false,
            archive: $archive_name,
            size: null,
            error: ($result.stderr | str trim)
        }
    }
}

# Upload to S3
def upload-to-s3 [
    file_path: string
    s3_bucket: string
    s3_prefix: string
]: record {
    print $"Uploading to S3 [$s3_bucket]..."

    let s3_key = $"($s3_prefix)/configs-$(get-timestamp).tar.gz"
    let result = do {
        ^aws s3 cp $file_path \
            $"s3://($s3_bucket)/($s3_key)" \
            --sse AES256 \
            --metadata "backup-type=config,timestamp=$(get-timestamp)"
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true,
            s3_location: $"s3://($s3_bucket)/($s3_key)",
            error: null
        }
    } else {
        {
            success: false,
            s3_location: $"s3://($s3_bucket)/($s3_key)",
            error: ($result.stderr | str trim)
        }
    }
}

# Main backup function
def main [
    --namespace: string = ""
    --s3-bucket: string = ""
    --s3-prefix: string = "backups/config"
    --work-dir: string = "/tmp/vapora-config-backups"
    --keep-local: bool = false
]: void {
    print "=== VAPORA Configuration Backup ==="
    print ""

    # Get namespace
    let ns = if ($namespace == "") {
        get-namespace
    } else {
        $namespace
    }

    # Validate environment
    if ($s3_bucket == "") {
        print "ERROR: --s3-bucket is required"
        exit 1
    }

    # Create working directory
    let work_path = $"($work_dir)/$(get-timestamp)"
    let result_create = do {
        ^mkdir -p $work_path 2>&1
    } | complete

    if ($result_create.exit_code != 0) {
        print "ERROR: Failed to create working directory"
        exit 1
    }

    # Backup all configuration types
    let configmaps_result = (backup-configmaps $work_path $ns)
    if (not $configmaps_result.success) {
        print $"WARNING: ConfigMap backup failed: ($configmaps_result.error)"
    } else {
        print $"✓ Backed up ($configmaps_result.count) ConfigMaps"
    }

    let secrets_result = (backup-secrets $work_path $ns)
    if (not $secrets_result.success) {
        print $"WARNING: Secret backup failed: ($secrets_result.error)"
    } else {
        print $"✓ Backed up ($secrets_result.count) Secrets"
    }

    let deployments_result = (backup-deployments $work_path $ns)
    if (not $deployments_result.success) {
        print $"WARNING: Deployment backup failed: ($deployments_result.error)"
    } else {
        print $"✓ Backed up deployments"
    }

    let networking_result = (backup-networking $work_path $ns)
    if (not $networking_result.success) {
        print $"WARNING: Networking backup failed: ($networking_result.error)"
    } else {
        print $"✓ Backed up networking resources"
    }

    # Compress backups
    let compress_result = (compress-backups $work_path)
    if (not $compress_result.success) {
        print $"ERROR: Compression failed: ($compress_result.error)"
        exit 1
    }

    print "✓ Backups compressed successfully"

    # Upload to S3
    let upload_result = (upload-to-s3 $compress_result.archive $s3_bucket $s3_prefix)
    if (not $upload_result.success) {
        print $"ERROR: S3 upload failed: ($upload_result.error)"
        exit 1
    }

    print "✓ Configuration backup uploaded to S3"

    # Cleanup unless requested to keep
    if (not $keep_local) {
        let cleanup = do {
            ^rm -rf $work_dir 2>&1
        } | complete

        if ($cleanup.exit_code == 0) {
            print "✓ Temporary files cleaned up"
        }
    } else {
        print $"Local backup kept at: ($work_dir)"
    }

    # Summary
    print ""
    print "=== Backup Complete ==="
    print $"Location: ($upload_result.s3_location)"
    print $"Namespace: ($ns)"
    print $"Timestamp: $(get-timestamp)"
}
