#!/usr/bin/env nu
# Assemble a transportable distro tarball from the single manifest
# provisioning/distro.ncl — the one source of truth shared with the Dockerfiles
# (image_only) and content.nu (content_hot).
#
# The tarball is the PV payload (site_tree) plus the active profile's image_only
# artifacts: the Leptos WASM pkg/ for leptos-hydration, nothing for htmx-ssr.
# Unpacked at /var/www/site/ it is exactly what the content-agnostic image
# expects on its PV.
#
# Profile is auto-detected from rendering.ncl (same source as `just build-auto`)
# unless given explicitly. website.css is rebuilt first so site/public/styles is
# current — both profiles serve it from the PV.
#
# Usage:
#   nu scripts/build/distro.nu [profile]      # profile: leptos-hydration | htmx-ssr
#   nu scripts/build/distro.nu --out dist --skip-css

def detect-profile [project_root: string]: nothing -> string {
    let dev_root = ($env.DEV_ROOT? | default "/Users/Akasha/Development")
    let detector = $"($dev_root)/rustelo/scripts/check-wasm-needed.nu"
    if ($detector | path exists) {
        let res = (do {
            cd $project_root
            ^nu $detector --routes-dir site/config --workspace-config site/config/rendering.ncl
        } | complete)
        match $res.exit_code {
            0 => "leptos-hydration"
            1 => "htmx-ssr"
            _ => { error make { msg: $"check-wasm-needed.nu failed: ($res.stderr | str trim)" } }
        }
    } else {
        open $"($project_root)/site/config/rendering.ncl"
            | parse --regex 'default_profile = "(?P<p>[^"]+)"' | get p?.0? | default "leptos-hydration"
    }
}

def pick-tar []: nothing -> string {
    let gtar = (do { ^which gtar } | complete)
    if $gtar.exit_code == 0 { ($gtar.stdout | str trim) } else { "tar" }
}

def main [
    profile?: string
    --out: string = "dist"
    --skip-css
]: nothing -> nothing {
    let project_root = ($env.FILE_PWD | path dirname | path dirname)  # scripts/build → root
    let manifest     = $"($project_root)/provisioning/distro.ncl"

    if not ($manifest | path exists) { error make { msg: $"manifest not found: ($manifest)" } }

    let resolved = if ($profile | is-not-empty) {
        if $profile not-in ["leptos-hydration" "htmx-ssr"] {
            error make { msg: $"invalid profile '($profile)' (leptos-hydration | htmx-ssr)" }
        }
        $profile
    } else {
        detect-profile $project_root
    }
    print $"profile:    ($resolved)"

    let distro      = (^nickel export $manifest --format json | from json)
    let site_tree   = $distro.site_tree
    let image_only  = ($distro.image_only | get $resolved)
    let wanted      = ($site_tree ++ $image_only)

    # Refresh website.css so the PV-served stylesheet matches current sources.
    if not $skip_css {
        print "css:        rebuilding (pnpm run css:build)"
        do { cd $project_root; ^pnpm run css:build } | complete
            | if $in.exit_code != 0 { error make { msg: "css:build failed" } } else { ignore }
    }

    let present = ($wanted | where { |p| ($project_root | path join $p) | path exists })
    let missing = ($wanted | where { |p| not (($project_root | path join $p) | path exists) })
    for m in $missing {
        if ($m | str contains "pkg") {
            print $"(ansi yellow)warning:(ansi reset) ($m) missing — run `cargo leptos build --release` first for leptos-hydration"
        } else {
            print $"(ansi yellow)warning:(ansi reset) manifest path absent: ($m)"
        }
    }
    if ($present | is-empty) { error make { msg: "nothing to pack — all manifest paths absent" } }

    let timestamp = (date now | format date "%Y%m%dT%H%M%S")
    let git_sha   = (do { cd $project_root; ^git rev-parse --short HEAD } | complete
        | if $in.exit_code == 0 { $in.stdout | str trim } else { "unknown" })

    # Normalise both sources into the PV layout rooted at /var/www. Source paths
    # diverge (site/* are already PV-shaped; the Leptos pkg is at target/site/pkg
    # but must land at site/pkg next to the binary's WASM). Stage so the archive
    # is the merged tree — unpacked with `tar -C /var/www` like content.nu does.
    let stage = (^mktemp -d | str trim)
    for src in $present {
        let dest = if ($src | str starts-with "target/site/") {
            $src | str replace "target/site/" "site/"
        } else { $src }
        let dest_abs = ($stage | path join $dest)
        mkdir ($dest_abs | path dirname)
        ^cp -R ($project_root | path join $src) $dest_abs
    }

    let out_dir = if ($out | str starts-with "/") { $out } else { $project_root | path join $out }
    mkdir $out_dir
    let outfile      = $"($out_dir)/website-($resolved)-($timestamp).tgz"
    let manifest_out = $"($out_dir)/website-($resolved)-($timestamp).manifest.json"

    {
        version: $timestamp, profile: $resolved, git_sha: $git_sha,
        site_tree: $site_tree, image_only: $image_only, packed: $present,
    } | to json | save -f $manifest_out

    let tar_bin = (pick-tar)
    do { ^$tar_bin --exclude='.DS_Store' -czf $outfile -C $stage site } | complete
        | if $in.exit_code != 0 { ^rm -rf $stage; error make { msg: "tar failed" } } else { ignore }
    ^rm -rf $stage

    let size = (ls $outfile | get size | first)
    print $"(ansi green)✅(ansi reset) ($outfile) (($size))"
    print $"   manifest: ($manifest_out)"
    print $"   layout:   archive root = site/  →  unpack with: tar -xzf <tarball> -C /var/www"
}
