#!/usr/bin/env nu

# Vendor htmx + extensions declared in templates/shared/htmx/htmx.lock.toml.
#
# Usage:
#   nu scripts/vendor-htmx.nu              # re-download every file listed in the lockfile
#   nu scripts/vendor-htmx.nu --verify     # only verify SHA-384 of files already on disk
#   nu scripts/vendor-htmx.nu --update X.Y # bump runtime + all extensions to version X.Y and refresh hashes

const LOCKFILE = "templates/shared/htmx/htmx.lock.toml"
const HTMX_DIR = "templates/shared/htmx"

def main [
    --verify    # do not download; only check existing files match recorded hashes
    --update: string  # bump runtime version, re-download all entries, rewrite the lockfile
] {
    let lock = open $LOCKFILE

    if $update != null {
        update_runtime $lock $update
        return
    }

    let runtime_entry = {
        file: $lock.runtime.file,
        source_url: $lock.runtime.source_url,
        sha384: $lock.runtime.sha384,
        size_bytes: $lock.runtime.size_bytes,
    }

    let all_entries = [$runtime_entry] | append (
        $lock.extensions | each {|e|
            {
                file: $e.file,
                source_url: $e.source_url,
                sha384: $e.sha384,
                size_bytes: $e.size_bytes,
            }
        }
    )

    if $verify {
        verify_all $all_entries
    } else {
        download_all $all_entries
    }
}

def download_all [entries: list] {
    for entry in $entries {
        let path = ($HTMX_DIR | path join $entry.file)
        let parent = ($path | path dirname)
        mkdir $parent
        ^curl -sSfL --max-time 30 -o $path $entry.source_url
        let actual = (^shasum -a 384 $path | split row " " | first)
        if $actual != $entry.sha384 {
            print $"FAIL ($entry.file): expected ($entry.sha384), got ($actual)"
            exit 1
        }
        let size = $entry.size_bytes
        print $"OK ($entry.file) ($size) bytes"
    }
}

def verify_all [entries: list] {
    mut failures = 0
    for entry in $entries {
        let path = ($HTMX_DIR | path join $entry.file)
        if not ($path | path exists) {
            print $"MISSING ($entry.file)"
            $failures = $failures + 1
            continue
        }
        let actual = (^shasum -a 384 $path | split row " " | first)
        if $actual != $entry.sha384 {
            print $"MISMATCH ($entry.file): expected ($entry.sha384), got ($actual)"
            $failures = $failures + 1
        } else {
            print $"OK ($entry.file)"
        }
    }
    if $failures > 0 {
        print $"($failures) failure(s)"
        exit 1
    }
}

def update_runtime [lock, new_version: string] {
    let new_runtime_url = $"https://unpkg.com/htmx.org@($new_version)/dist/htmx.min.js"
    print $"Updating htmx runtime to ($new_version)"
    let runtime_path = ($HTMX_DIR | path join $lock.runtime.file)
    ^curl -sSfL --max-time 30 -o $runtime_path $new_runtime_url
    let runtime_hash = (^shasum -a 384 $runtime_path | split row " " | first)
    let runtime_size = (ls $runtime_path | first | get size | into int)
    print $"Wrote runtime: ($runtime_hash) ($runtime_size) bytes"
    print "Edit templates/shared/htmx/htmx.lock.toml manually with the new version/hash/size, then re-run --verify."
}
