#!/usr/bin/env nu
# extract-template.nu — derive a website template from a living model project
# (jpl-website) as a sanitized snapshot with safe defaults + COMPLETE markers.
#
# Reproducible seed for templates/website-htmx-ssr and templates/website-leptos.
# Re-run to re-snapshot when the model evolves (snapshot model, not a live mirror).
#
#   nu extract-template.nu --mode htmx-ssr --out ../templates/website-htmx-ssr
#   nu extract-template.nu --mode leptos   --out ../templates/website-leptos
#
# Design:
#   - crate names stay neutral ("website-*"); the generator renames to the chosen
#     project later. Only the jpl-named pages_htmx crate is normalised to website-*.
#   - deploy identity (domain, registry, secrets base, author) is replaced with
#     safe defaults so NCL still parses and the site runs, each marked COMPLETE.
#   - jesusperez portfolio pages and real content are pruned to generic examples.

# Binary / huge extensions to skip during sanitization (everything else is text).
def binary-ext [] {
  [png jpg jpeg gif ico svg webp avif woff woff2 ttf otf eot wasm db "db-shm" "db-wal" pdf zip tgz gz xz lock map]
}

# Ordered, specific-before-generic substitutions applied to text files.
def subs [] {
  [
    # crate normalisation (the one jpl-named crate)
    ["jpl-pages-htmx" "website-pages-htmx"]
    ["jpl_pages_htmx" "website_pages_htmx"]
    ["jpl-website" "website"]
    ["jpl_website" "website"]
    # deploy identity → safe defaults (COMPLETE: set to your own)
    ["hello@jesusperez.pro" "hello@example.com"]
    ["dev@jesusperez.pro" "dev@example.com"]
    ["repo.jesusperez.pro/jesus" "repo.example.com/org"]
    ["daoreg.librecloud.online" "registry.example.com"]
    ["daoreg" "registry"]
    ["reg.librecloud.online" "registry.example.com"]
    ["librecloud.online" "example.com"]
    ["jesusperez.pro" "example.com"]
    ["reg-librecloud-pull" "registry-pull-secret"]
    ["librecloud-fip-wuji" "gateway-fip"]
    ["libre-wuji" "secrets-base"]
    ["librecloud" "example"]
    ["jesusperezlorenzo" "example-org"]
    ["@jesusperez_dev" "@example_dev"]
    ["JesusPerez" "ExampleOrg"]
    ["jesusperez" "example"]
  ]
}

def main [
  --mode: string = "htmx-ssr"   # htmx-ssr | leptos
  --src: string = "/Users/Akasha/Development/jpl-website"
  --out: string                 # target template dir (required)
] {
  if ($out | is-empty) { error make { msg: "--out is required" } }
  if ($mode not-in ["htmx-ssr" "leptos"]) { error make { msg: $"bad --mode ($mode)" } }
  let src = ($src | path expand)
  let out = ($out | path expand)
  if not ($src | path exists) { error make { msg: $"src not found: ($src)" } }

  print $"[extract] mode=($mode) src=($src) out=($out)"
  if ($out | path exists) { rm -rf $out }
  mkdir $out

  # --- 1. rsync the tree with explicit excludes -------------------------------
  let common_excludes = [
    ".git/" ".gitignore" "target/" "node_modules/" ".env" ".env.dev" ".k"
    "cache/" "dist/" "works-pv/" "lian-build-out/" ".DS_Store"
    ".ontoref/" ".ontoref-backup-pre-0023.tgz" ".coder/" ".config/" ".cargo/"
    ".claude/" ".rustelo.ontoref/" ".woodpecker/"
    "Cargo.lock" "pnpm-lock.yaml" "rel.sh" "RESUME.md" "test_img_gen.sh"
    "card.ncl" "rustelo-deps-overlay.toml"
    # jpl-only top-level cruft
    "data/" "rustelo/" "crates/site/" "templates/" ".woodpecker/" ".npmrc"
    "just/claude-admin.just" "just/claude-content.just" "just/claude-dev.just"
    # cluster/workspace-specific deploy bundles — a new site generates its own
    "provisioning/workspaces/" "provisioning/rustelo_website/"
    # real content — replaced by seed example post + pruned extras
    "site/content/blog/"
    "site/content/projects/" "site/content/recipes/" "site/content/activities/"
    "site/guide/" "site/info/" "site/reflection/" "site/public/kitdigital/"
    "site/public/r/" "site/public/content/" "site/public/docs/"
    # build artifacts in lian-build
    "lian-build/save/" "lian-build/all_Dockerfile" "lian-build/Dockerfile.server"
    "lian-build/build_directives_server.ncl"
    # jesusperez portfolio pages (htmx j2)
    "crates/pages_htmx/templates/pages/kogral.j2"
    "crates/pages_htmx/templates/pages/ontoref.j2"
    "crates/pages_htmx/templates/pages/provisioning.j2"
    "crates/pages_htmx/templates/pages/rustelo.j2"
    "crates/pages_htmx/templates/pages/secretumvault.j2"
    "crates/pages_htmx/templates/pages/stratumiops.j2"
    "crates/pages_htmx/templates/pages/syntaxis.j2"
    "crates/pages_htmx/templates/pages/typedialog.j2"
    "crates/pages_htmx/templates/pages/vapora.j2"
    # jpl logos (binary, name-bearing)
    "site/assets/logos/" "site/public/images/logos/"
  ]
  # NOTE: crates are NOT split by mode. jpl's server hard-depends on website-pages
  # and optionally website-client; mode is selected via cargo features + cfg, not
  # crate membership. Both templates carry the full workspace; only rendering.ncl
  # default_profile, the kept Dockerfile, and build features differ. (A pure-htmx
  # site can prune the leptos crates later only after making those deps optional.)
  let excludes = $common_excludes
  let exfile = (mktemp -t rsync-ex.XXXXXX)
  $excludes | str join "\n" | save -f $exfile
  (^rsync -a --exclude-from $exfile $"($src)/" $"($out)/")
  rm -f $exfile

  # --- 2. sanitize text files -------------------------------------------------
  let bin = (binary-ext)
  let files = (glob ($out | path join "**" "*") --no-dir
    | where { |f| (($f | path parse | get extension) not-in $bin) and (not ($f | str contains "node_modules")) })
  let table = (subs)
  mut done = 0
  for f in $files {
    try {
      mut content = (open --raw $f | decode utf-8)
      for pair in $table {
        $content = ($content | str replace --all ($pair | get 0) ($pair | get 1))
      }
      $content | save -f $f
      $done = $done + 1
    } catch {
      # binary or non-utf8 file — leave untouched
    }
  }
  print $"[extract] sanitized ($done) / ($files | length) text files"

  # --- 3. mode-specific tweaks ------------------------------------------------
  # rendering profile default
  let rendering = ($out | path join "site" "config" "rendering.ncl")
  if ($rendering | path exists) {
    let want = (if $mode == "htmx-ssr" { "htmx-ssr" } else { "leptos-hydration" })
    open --raw $rendering | decode utf-8 | str replace --all --regex 'default_profile\s*=\s*"[^"]*"' $'default_profile = "($want)"' | save -f $rendering
  }
  # workspace members are left as-is (full workspace; see note above).
  # drop the non-active Dockerfile (rsync excludes are unreliable for single files here)
  let drop_dockerfile = (if $mode == "htmx-ssr" { "Dockerfile.leptos-hydration" } else { "Dockerfile.htmx-ssr" })
  let df = ($out | path join "lian-build" $drop_dockerfile)
  if ($df | path exists) { rm -f $df }

  # --- 4. overlay seed (example content, setup doc) ---------------------------
  let seed = ($env.FILE_PWD | path join "seed" "common")
  if ($seed | path exists) {
    ^rsync -a $"($seed)/" $"($out)/"
    print $"[extract] seed overlaid from ($seed)"
  }

  print $"[extract] done: ($out)"
}
