#!/usr/bin/env nu
# Unpack - Extract and validate distribution bundles
#
# Usage:
#   nu scripts/provisioning/unpack.nu bundle.tar.gz
#   nu scripts/provisioning/unpack.nu --bundle bundle.tar.gz --dest ./extracted
#

use common/validate.nu *

def show-help [] {
    let help_text = "
syntaxis Unpack - Extract and validate distribution bundles

USAGE:
  nu scripts/provisioning/unpack.nu [OPTIONS] [BUNDLE]

ARGUMENTS:
  BUNDLE                Bundle file to extract (.tar.gz or .zip)

OPTIONS:
  --bundle <FILE>       Bundle file path (alternative to positional argument)
  --dest <DIR>          Extraction destination directory
                        Default: current directory
  --verify              Verify checksums after extraction
  --list-contents       Show bundle contents without extracting
  --help                Show this help message

EXAMPLES:
  # Extract bundle to current directory
  nu scripts/provisioning/unpack.nu bundle.tar.gz

  # Extract to specific directory
  nu scripts/provisioning/unpack.nu --bundle bundle.tar.gz --dest ./extracted

  # List bundle contents
  nu scripts/provisioning/unpack.nu --list-contents bundle.tar.gz

  # Extract and verify checksums
  nu scripts/provisioning/unpack.nu bundle.tar.gz --verify
"
    print $help_text
}

def detect-bundle-format [bundle_file: path] {
    let ext = ($bundle_file | path parse | get extension)
    match $ext {
        "gz" => { "tar.gz" }
        "zip" => { "zip" }
        _ => { let msg = "Unknown bundle format: " + $ext
error make {msg: $msg} }
    }
}

def extract-bundle [bundle_file: path, dest_dir: path, format: string] {
    print ("📦 Extracting " + $format + " bundle...")

    ^mkdir -p $dest_dir

    match $format {
        "tar.gz" => {
            ^tar -xzf $bundle_file -C $dest_dir
            print "✅ Extraction complete"
        }
        "zip" => {
            ^unzip -q $bundle_file -d $dest_dir
            print "✅ Extraction complete"
        }
        _ => {
            let msg = "Unsupported format: " + $format
error make {msg: $msg}
        }
    }
}

def find-manifest [dest_dir: path] {
    let manifest_file = ($dest_dir | path join "*" "manifest.toml")
    let matching_files = (glob $manifest_file)

    if (($matching_files | length) == 0) {
        error make {msg: "No manifest found in bundle"}
    }

    $matching_files.0
}

def show-bundle-info [manifest_file: path] {
    let manifest = try {
        open --raw $manifest_file | from toml
    } catch {
        let msg = "Failed to read manifest: " + ($manifest_file | into string)
error make {msg: $msg}
    }

    print ""
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print "📦 Bundle Information"
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print ("Version:    " + ($manifest.bundle.version | into string))
    print ("Target:     " + ($manifest.bundle.target | into string))
    print ("Format:     " + ($manifest.bundle.format | into string))
    print ("Created:    " + ($manifest.bundle.created_at | into string))
    print ""

    print "Artifacts:"
    print ("  Binaries: " + (($manifest.artifacts.binaries | length) | into string))
    $manifest.artifacts.binaries | each { |bin|
        print ("    - " + ($bin | into string))
    }
    print ("  Configs: " + (($manifest.artifacts.configs | length) | into string))
    $manifest.artifacts.configs | each { |cfg|
        print ("    - " + ($cfg | into string))
    }
    print ("  Docs: " + (($manifest.artifacts.docs | length) | into string))
    $manifest.artifacts.docs | each { |doc|
        print ("    - " + ($doc | into string))
    }
    print ""
    print ("Checksums:  " + (($manifest.checksums | length) | into string))
    print ""
}

def verify-bundle [dest_dir: path, manifest_file: path] {
    print "🔍 Verifying bundle checksums..."

    let bundle_root = ($manifest_file | path dirname)
    let checksums_file = ($bundle_root | path join ".." "*.checksums.toml")
    let matching_checksums = (glob $checksums_file)

    if (($matching_checksums | length) == 0) {
        print "⚠️  No checksums file found - skipping verification"
        return
    }

    let checksums_path = $matching_checksums.0
    let verify_result = (verify-checksums $checksums_path $bundle_root)

    if ($verify_result.failed == 0) {
        print ("✅ All " + ($verify_result.verified | into string) + " checksums verified")
    } else {
        print ("❌ " + ($verify_result.failed | into string) + " checksum mismatches found")
        print "Failed files:"
        $verify_result.errors | each { |err|
            print ("  - " + $err.file + ": expected " + ($err.expected | str substring 0..8) + "... got " + ($err.actual | str substring 0..8) + "...")
        }
    }
}

def list-bundle-contents [bundle_file: path, format: string] {
    print ("📋 Contents of " + ($bundle_file | path basename) + ":")
    print ""

    match $format {
        "tar.gz" => {
            ^tar -tzf $bundle_file | each { |line|
                print ("  " + $line)
            }
        }
        "zip" => {
            ^unzip -l $bundle_file | lines | skip 3 | drop 2 | each { |line|
                let trimmed = ($line | str trim)
                if (($trimmed | str length) > 0) {
                    print ("  " + $line)
                }
            }
        }
        _ => {
            let msg = "Unsupported format: " + $format
error make {msg: $msg}
        }
    }

    print ""
}

# Main entry point
def main [bundle: string = "", --bundle: path = "", --dest: path = ".", --verify = false, --list-contents = false, --help = false] {
    if $help {
        show-help
        return
    }

    # Determine bundle file
    let bundle_file = if ($bundle != "") {
        $bundle
    } else if ($bundle != "") {
        $bundle
    } else {
        error make {msg: "Bundle file must be specified"}
    }

    if (not (($bundle_file | path exists))) {
        let msg = "Bundle file not found: " + ($bundle_file | into string)
error make {msg: $msg}
    }

    # Validate bundle
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print "🔍 syntaxis Unpack"
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print ("Bundle:  " + ($bundle_file | path basename))
    print ("Size:    " + (((ls $bundle_file | get size.0) | into int) / (1024 * 1024) | math round --precision 2 | into string) + " MB")
    print ""

    let format = (detect-bundle-format $bundle_file)

    # Validate bundle structure
    let validation = (validate-bundle-structure $bundle_file)
    if (not ($validation.valid)) {
        print "❌ Bundle validation failed:"
        $validation.errors | each { |err|
            print ("  - " + $err)
        }
        error make {msg: "Invalid bundle"}
    }
    print ("✅ Bundle format valid: " + $format)
    print ""

    # List contents if requested
    if $list_contents {
        list-bundle-contents $bundle_file $format
        return
    }

    # Extract bundle
    extract-bundle $bundle_file $dest $format

    # Find and display manifest
    let manifest_file = (find-manifest $dest)
    show-bundle-info $manifest_file

    # Verify if requested
    if $verify {
        verify-bundle $dest $manifest_file
    }

    print "📂 Extracted to: " + ($dest | into string)
    print ""
}

