#!/usr/bin/env nu
# Write tenant registration stubs to a workspace repo.
# Usage: nu provisioning/register.nu --workspace <path> [--workspace-name secrets-base]
# Env: DEV_ROOT, PROVISIONING, LIAN_BUILD_ROOT
#
# Writes (with VALUES INLINED — no cross-repo NCL imports at workspace eval time):
#   <workspace>/appserv/<ws-name>/<tenant>.ncl
#   <workspace>/builds/<tenant>.ncl
#
# NEVER touches infra/settings.ncl, apps.ncl, or platform.ncl.
# Idempotent: re-run with unchanged inputs is a no-op.

def ncl-str [v: string]: nothing -> string { $'"($v)"' }
def ncl-bool [v: bool]: nothing -> string { if $v { "true" } else { "false" } }
def ncl-int [v: int]: nothing -> string { $"($v)" }
def ncl-sym [v: string]: nothing -> string { $"'($v)" }

def comma-quoted [items: list<string>]: nothing -> string {
    $items | each { |s| $'"($s)"' } | str join ", "
}

def project-git-sha [project_root: string]: nothing -> string {
    do { ^git -C $project_root rev-parse --short HEAD } | complete
        | if $in.exit_code == 0 { $in.stdout | str trim } else { "unknown" }
}

def extract-stub-sha [path: string]: nothing -> string {
    if not ($path | path exists) { return "" }
    let matches = (open $path | lines | where { |l| $l | str starts-with "# source:" })
    if ($matches | is-empty) { return "" }
    let parts = ($matches | first | split row " @ ")
    if ($parts | length) < 2 { return "" }
    $parts | last | str trim
}

def check-and-write [path: string, content: string, sha: string, label: string]: nothing -> nothing {
    let existing_sha = (extract-stub-sha $path)
    if ($existing_sha | is-not-empty) {
        if $existing_sha == $sha {
            let existing = (open $path)
            if $existing == $content {
                print $"[register] ($label): no change at ($sha) — skipping"
                return
            }
            print $"[register] WARNING: ($label) was edited manually since last register at ($sha) — overwriting"
        } else {
            print $"[register] ($label): updating ($existing_sha) → ($sha)"
        }
    }
    let parent = ($path | path dirname)
    if not ($parent | path exists) {
        mkdir $parent
    }
    $content | save -f $path
    print $"[register] wrote ($path)"
}

def make-appserv-stub [
    p: record
    ws: record
    sha: string
    project_root: string
    overrides_rel: string
    ws_name: string
]: nothing -> string {
    let creds_list    = (comma-quoted $p.requires.credentials)
    let endpoints     = (comma-quoted $p.provides.endpoints)
    let sec_concerns  = (comma-quoted $p.context.security.concerns)
    let upd_holds     = (comma-quoted $p.context.updates.holds)
    let alerts        = (comma-quoted $p.context.supervision.alerts)

    $"# source: ($project_root) @ ($sha)
# overrides: provisioning/workspaces/($ws_name).overrides.ncl
# generated: nu provisioning/register.nu — re-run to update; do not edit manually
let ext = import \"catalog/components/rustelo_website/nickel/main.ncl\" in

\{
  website = ext.make_rustelo_website \{
    name            = (ncl-str $p.name),
    namespace       = (ncl-str $p.namespace),
    image           = (ncl-str $p.image_base),
    image_tag       = (ncl-str $p.image_tag),
    port            = (ncl-int $p.port),
    domain          = (ncl-str $p.domain),
    dns_zone        = (ncl-str $p.dns_zone),
    acme_email      = (ncl-str $p.acme_email),
    cluster_issuer  = (ncl-str $ws.cluster_issuer),
    gateway_fip     = (ncl-str $ws.gateway_fip),
    gateway_name    = (ncl-str $ws.gateway_name),
    gateway_ns      = (ncl-str $ws.gateway_ns),
    registry_secret = (ncl-str $ws.registry_secret),

    data_pvc = \{
      enabled       = (ncl-bool $p.data_pvc.enabled),
      size          = (ncl-str $p.data_pvc.size),
      mount_path    = (ncl-str $p.data_pvc.mount_path),
      storage_class = (ncl-str $p.data_pvc.storage_class),
    \},

    requires = \{
      storage     = \{ size = (ncl-str $p.requires.storage.size), persistent = (ncl-bool $p.requires.storage.persistent) \},
      ports       = [\{ port = (ncl-int $p.port), exposure = 'public \}],
      credentials = [($creds_list)],
    \},

    provides = \{
      service   = (ncl-str $p.provides.service),
      port      = (ncl-int $p.provides.port),
      endpoints = [($endpoints)],
    \},

    operations = \{
      install = (ncl-bool $p.operations.install),
      update  = (ncl-bool $p.operations.update),
      delete  = (ncl-bool $p.operations.delete),
      health  = (ncl-bool $p.operations.health),
    \},

    context = \{
      how      = (ncl-str $p.context.how),
      why      = (ncl-str $p.context.why),
      priority = (ncl-sym $p.context.priority),
      security = \{
        posture  = (ncl-sym $p.context.security.posture),
        tls      = (ncl-bool $p.context.security.tls),
        concerns = [($sec_concerns)],
      \},
      supervision = \{
        health_check = (ncl-bool $p.context.supervision.health_check),
        metrics      = (ncl-bool $p.context.supervision.metrics),
        alerts       = [($alerts)],
      \},
      updates = \{
        policy = (ncl-sym $p.context.updates.policy),
        holds  = [($upd_holds)],
      \},
    \},
  \},
\}
"
}

def make-builds-stub [
    p: record
    sha: string
    project_root: string
    dev_root: string
]: nothing -> string {
    let image_ref   = $"($p.image_base):($p.image_tag)"
    let context_src = $"($dev_root)/website"
    $"# source: ($project_root) @ ($sha)
# generated: nu provisioning/register.nu — do not edit manually
let ext = import \"catalog/components/lian_build/nickel/main.ncl\" in

\{
  lian_build = ext.make_lian_build \{
    workspace   = (ncl-str $p.workspace_id),
    image       = (ncl-str $image_ref),
    context_src = (ncl-str $context_src),
    ctx_type    = (ncl-sym ($p.ctx_type | into string)),
  \},
\}
"
}

def main [
    --workspace: string = ""
    --workspace-name: string = "secrets-base"
    --image-tag: string = ""
]: nothing -> nothing {
    if ($workspace | is-empty) {
        error make { msg: "Usage: nu provisioning/register.nu --workspace <secrets-base-infra-path> [--image-tag X.Y.Z]" }
    }
    if not ($workspace | path exists) {
        error make { msg: $"workspace path not found: ($workspace)" }
    }

    let dev_root     = ($env.DEV_ROOT? | default "/Users/Akasha/Development")
    let prov         = ($env.PROVISIONING? | default $"($dev_root)/project-provisioning/provisioning")
    let lb_root      = ($env.LIAN_BUILD_ROOT? | default $"($dev_root)/lian-build")
    let project_root = ($env.FILE_PWD | path dirname)
    let overrides    = $"($project_root)/provisioning/workspaces/($workspace_name).overrides.ncl"

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

    let p_raw = (
        ^nickel export
            --import-path $prov
            --import-path $lb_root
            $"($project_root)/provisioning/project.ncl"
            --format json
        | from json
    )
    let p = if ($image_tag | is-not-empty) { $p_raw | update image_tag $image_tag } else { $p_raw }
    let ws = (
        ^nickel export
            --import-path $prov
            $overrides
            --format json
        | from json
    )

    let sha = (project-git-sha $project_root)
    let tenant = ($p.name | str replace -a "-" "_")

    let appserv_path = $"($workspace)/appserv/($workspace_name)/($p.name).ncl"
    let builds_path  = $"($workspace)/builds/($tenant).ncl"

    let appserv_content = (make-appserv-stub $p $ws $sha $project_root $overrides $workspace_name)
    let builds_content  = (make-builds-stub $p $sha $project_root $dev_root)

    check-and-write $appserv_path $appserv_content $sha "appserv"
    check-and-write $builds_path  $builds_content  $sha "builds"

    print $"[register] done — tenant: ($p.name), workspace: ($workspace_name), sha: ($sha)"
}
