#!/usr/bin/env nu
# new-site.nu — scaffold a new Rustelo website from a self-contained template.
#
# Interactive:   nu new-site.nu
# Non-interactive (InitConfig-style, like `cargo rustelo init --config`):
#   nu new-site.nu --project acme --render-mode htmx-ssr --domain acme.dev \
#       --site-title "Acme" --languages "en,es" --default-lang en --ontoref minimal --yes
#
# The site is created as a sibling of the rustelo repo (constellation or flat).
# All {{RUSTELO_ROOT}} placeholders in template files are replaced with the
# correct relative path from each file's execution context to the framework root.

def fw-root [] { $env.FILE_PWD | path join ".." ".." | path expand }

def ask [prompt: string, default: string] {
  let ans = (input $"($prompt) [($default)]: ")
  if ($ans | str trim | is-empty) { $default } else { ($ans | str trim) }
}

def snake [s: string] { $s | str replace --all "-" "_" }

# Compute the relative path from directory `from` to directory `to`.
# Both must be absolute expanded paths.
def rel-path [from: string, to: string] {
  let from_parts = ($from | path split | where { |p| ($p | str length) > 0 })
  let to_parts   = ($to   | path split | where { |p| ($p | str length) > 0 })
  let min_len    = ([$from_parts $to_parts] | each { length } | math min)
  mut common = 0
  for i in 0..<$min_len {
    if ($from_parts | get $i) == ($to_parts | get $i) {
      $common = ($common + 1)
    } else {
      break
    }
  }
  let ups   = ($from_parts | length) - $common
  let down  = ($to_parts | skip $common)
  let parts = ((0..<$ups | each { ".." }) ++ $down)
  if ($parts | is-empty) { "." } else { $parts | str join "/" }
}

# Replace {{RUSTELO_ROOT}} in every text file under `root` with the correct
# relative path from that file's execution-context directory to `fw`.
#
# Files under `workspace_root_dirs` (like justfiles/) run in the workspace
# root cwd context even though they sit in a subdirectory, so they receive the
# workspace-root-relative path rather than the file-directory-relative path.
def apply-rustelo-root [root: string, fw: string] {
  let bin = [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]
  let workspace_root_dirs = ["justfiles"]
  let files = (glob ($root | path join "**" "*") --no-dir
    | where { |f| ($f | path parse | get extension) not-in $bin }
    | where { |f| not ($f | str contains "node_modules") })
  for f in $files {
    try {
      let c = (open --raw $f | decode utf-8)
      if not ($c | str contains "{{RUSTELO_ROOT}}") { continue }
      let file_dir = ($f | path dirname)
      let rel_parts = ($file_dir | path relative-to $root | path split
                       | where { |p| ($p | str length) > 0 })
      let effective_dir = if (($rel_parts | length) > 0
                              and ($rel_parts | first) in $workspace_root_dirs) {
        $root
      } else {
        $file_dir
      }
      let rustelo_rel = (rel-path $effective_dir $fw)
      ($c | str replace --all "{{RUSTELO_ROOT}}" $rustelo_rel) | save -f $f
    } catch { }
  }
}

def main [
  --project: string = ""
  --render-mode: string = ""
  --site-title: string = ""
  --domain: string = ""
  --languages: string = ""
  --default-lang: string = ""
  --ontoref: string = ""
  --out: string = ""          # parent dir for the new site (default: sibling of fw repo)
  --yes                        # non-interactive: take provided flags / defaults
] {
  let fw = (fw-root)
  let opts = (^nickel export ($fw | path join "templates" "options.ncl") | from json)
  let defs = ($opts.questions | reduce --fold {} { |q, acc| $acc | insert $q.id $q.default })

  # resolve each answer: flag > prompt (interactive) > default
  let interactive = (not $yes)
  let project      = (if ($project      | is-not-empty) { $project      } else if $interactive { ask "Project name (kebab-case)"               $defs.project      } else { $defs.project      })
  let render_mode  = (if ($render_mode  | is-not-empty) { $render_mode  } else if $interactive { ask "Render mode (htmx-ssr|leptos-hydration)" $defs.render_mode  } else { $defs.render_mode  })
  let site_title   = (if ($site_title   | is-not-empty) { $site_title   } else if $interactive { ask "Site title"                              $defs.site_title   } else { $defs.site_title   })
  let domain       = (if ($domain       | is-not-empty) { $domain       } else if $interactive { ask "Domain (no scheme)"                      $defs.domain       } else { $defs.domain       })
  let languages    = (if ($languages    | is-not-empty) { $languages    } else if $interactive { ask "Languages (csv)"                         $defs.languages    } else { $defs.languages    })
  let default_lang = (if ($default_lang | is-not-empty) { $default_lang } else if $interactive { ask "Default language"                        $defs.default_lang } else { $defs.default_lang })
  let ontoref      = (if ($ontoref      | is-not-empty) { $ontoref      } else if $interactive { ask "ontoref onboarding (full|minimal|none)"  $defs.ontoref      } else { $defs.ontoref      })

  if ($render_mode not-in ($opts.template_for | columns)) {
    error make { msg: $"unknown render_mode ($render_mode); expected one of ($opts.template_for | columns)" }
  }
  let tmpl_name = ($opts.template_for | get $render_mode)
  let tmpl = ($fw | path join "templates" $tmpl_name)
  if not ($tmpl | path exists) { error make { msg: $"template not found: ($tmpl)" } }

  # Determine parent directory for the new site.
  # In constellation layout (fw basename == "code"), the fw repo root is one
  # level up, and the site should be a sibling of that repo root.
  let parent = if ($out | is-not-empty) {
    ($out | path expand)
  } else if (($fw | path basename) == "code") {
    $fw | path dirname | path dirname
  } else {
    $fw | path dirname
  }

  let dest = ($parent | path join $project)
  if ($dest | path exists) { error make { msg: $"destination exists: ($dest)" } }

  print $"[new-site] ($project)  mode=($render_mode)  → ($dest)"
  cp -r $tmpl $dest
  rm -f ($dest | path join "TEMPLATE-SETUP.md")  # re-added at end with status

  # Substitute {{RUSTELO_ROOT}} with the correct per-file relative path to fw
  apply-rustelo-root $dest $fw

  # --- rename crate identifiers website-* → <project>-*  (skip if project == website)
  if $project != "website" {
    let p = $project
    let ps = (snake $project)
    let renames = [
      ["website-pages-htmx" $"($p)-pages-htmx"] ["website_pages_htmx" $"($ps)_pages_htmx"]
      ["website-pages" $"($p)-pages"] ["website_pages" $"($ps)_pages"]
      ["website-client" $"($p)-client"] ["website_client" $"($ps)_client"]
      ["rustelo-htmx-server" $"($p)-htmx-server"] ["rustelo_htmx_server" $"($ps)_htmx_server"]
      ["rustelo-leptos-server" $"($p)-leptos-server"] ["rustelo_leptos_server" $"($ps)_leptos_server"]
      ["website-shared" $"($p)-shared"] ["website_shared" $"($ps)_shared"]
      ["name = \"website\"" $"name = \"($p)\""]   # leptos metadata output name
    ]
    sanitize-tree $dest $renames
  }

  # --- set deploy/identity values
  let domain_subs = [
    ["example.com" $domain]
  ]
  sanitize-tree $dest $domain_subs

  # --- ontoref onboarding
  let onto = ($env.FILE_PWD | path join "onto-onboard.nu")
  nu $onto --level $ontoref --root $dest --project $project --languages $languages --profile $render_mode

  # --- write a fresh setup checklist with the resolved values
  [
    $"# ($site_title) — generated site"
    ""
    $"- project: ($project)   render mode: ($render_mode)   languages: ($languages) (default ($default_lang))"
    $"- domain: ($domain)   ontoref: ($ontoref)"
    ""
    "## Remaining COMPLETE items"
    "- site/config/site.ncl — set site name (title) and languages/default_language."
    "- site/config/routes.ncl — your routes; content under site/content/."
    "- .env (copy from .env.example) — session secret, DB, SMTP/OAuth."
    "- provisioning/project.ncl + lian-build/build_directives.ncl — registry, namespace, secrets (search: example.com, registry.example.com, secrets-base)."
    "- Logos under site/public/images/logos/ + site/config/site.ncl logo.*"
    "- Replace the example post in site/content/blog/{en,es}/getting-started/."
    ""
    "Build:   just build-auto        (auto-detects profile)"
    "Pack:    just build::distro"
    "Verify:  cargo check"
  ] | str join "\n" | save -f ($dest | path join "SETUP.md")

  print ""
  print $"[new-site] done → ($dest)"
  print $"  next: cd ($dest); cat SETUP.md; cargo check"
}

# replace a list of [from to] pairs across all text files in a tree (binary-safe).
def sanitize-tree [root: string, pairs: list] {
  let bin = [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]
  let files = (glob ($root | path join "**" "*") --no-dir
    | where { |f| (($f | path parse | get extension) not-in $bin) and (not ($f | str contains "node_modules")) })
  for f in $files {
    try {
      mut c = (open --raw $f | decode utf-8)
      for pair in $pairs { $c = ($c | str replace --all ($pair | get 0) ($pair | get 1)) }
      $c | save -f $f
    } catch { }
  }
}
