#!/usr/bin/env fish

### --------- helpers ----------
function _need --description "ensure a command exists"
  for c in $argv
    if not type -q $c
      echo (set_color red)"Error:"(set_color normal)" missing command: $c" >&2
      return 1
    end
  end
end

function _banner --description "pretty section header" -a MSG
  set_color cyan; echo; echo "==> $MSG"; set_color normal
end

# 32-char alphanumeric generator (fast, no shell-specials)
function _rand_alnum32
  if type -q openssl
    openssl rand -base64 48 2>/dev/null | tr -dc 'A-Za-z0-9' | head -c 32
  else
    dd if=/dev/urandom bs=48 count=1 2>/dev/null | base64 | tr -dc 'A-Za-z0-9' | head -c 32
  end
end

# Default image chooser (you should override with your own multi-arch image)
function _sui_default_image -a NET
  echo registry.bstein.dev/crypto/sui-tools:1.53.2
end

# Convert any string to a k8s-safe name (RFC-1123 label-ish)
function _k8s_name --description "sanitize to RFC-1123 label" -a S
  set s (string lower -- $S)
  set s (string replace -ar -- '[^a-z0-9-]' '-' $s)
  set s (string replace -r  -- '^-+' ''      $s)
  set s (string replace -r  -- '-+$' ''      $s)
  echo $s
end

# Simple non-empty check
function _require --description "require a non-empty value" -a WHAT VAL
  if test -z "$VAL"
    echo (set_color red)"Error:"(set_color normal)" $WHAT cannot be empty. Aborting." >&2
    return 1
  end
end

function _sc_list --description "list storageclasses as menu"
  kubectl get storageclass -o json | jq -r '
    .items[]
    | {name: .metadata.name,
       provisioner: .provisioner,
       reclaim: (.reclaimPolicy // "Delete"),
       default: ( .metadata.annotations["storageclass.kubernetes.io/is-default-class"] == "true"
                  or .metadata.annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true") }
    | "\(.name)\t\(.provisioner)\t\(.reclaim)\t\((.default|tostring))"
  ' 2>/dev/null
end

# Choose StorageClass by index or name
function _choose_sc --description "interactive StorageClass picker"
  set lines (_sc_list)
  if test (count $lines) -eq 0
    echo (set_color red)"Error:"(set_color normal)" No StorageClasses found." >&2
    return 1
  end

  echo "" >&2
  echo "==> Available StorageClasses" >&2
  echo "  # | name                 | provisioner            | reclaim | default" >&2
  echo "----+----------------------+------------------------+---------+--------" >&2
  set i 1
  for l in $lines
    set name (echo $l | awk -F'\t' '{print $1}')
    set prov (echo $l | awk -F'\t' '{print $2}')
    set rec  (echo $l | awk -F'\t' '{print $3}')
    set def  (echo $l | awk -F'\t' '{print $4}')
    printf " %2d | %-20s | %-22s | %-7s | %s\n" $i $name $prov $rec $def >&2
    set i (math $i + 1)
  end

  set prefer (printf "%s\n" $lines | awk -F'\t' '$4=="true"{print $1}' | head -n1)
  if test -z "$prefer"
    set prefer (printf "%s\n" $lines | awk -F'\t' '{print $1}' | head -n1)
  end

  read -P "Pick StorageClass by number or name (blank = $prefer): " choice

  if test -z "$choice"
    echo "Using StorageClass: $prefer" >&2
    echo $prefer
    return 0
  end

  if string match -qr '^[0-9]+$' -- $choice
    set idx (math $choice)
    if test $idx -lt 1 -o $idx -gt (count $lines)
      echo (set_color red)"Error:"(set_color normal)" Choice out of range." >&2
      return 1
    end
    set sel (printf "%s\n" $lines[$idx] | awk -F'\t' '{print $1}')
    echo "Using StorageClass: $sel" >&2
    echo $sel
    return 0
  end

  set found (printf "%s\n" $lines | awk -F'\t' -v want="$choice" '$1==want{print $1}')
  if test -z "$found"
    echo (set_color red)"Error:"(set_color normal)" No StorageClass named '$choice'." >&2
    return 1
  end
  echo "Using StorageClass: $found" >&2
  echo $found
end

# ---- probe Sui JSON-RPC endpoint
function _probe_sui_rpc --description "probe Sui JSON-RPC endpoint" -a URL
  if test -z "$URL"
    echo (set_color red)"Error:"(set_color normal)" _probe_sui_rpc needs an URL" >&2
    return 1
  end
  set payload '{"jsonrpc":"2.0","id":1,"method":"sui_getLatestCheckpointSequenceNumber","params":[]}'
  set tmp (mktemp)
  set code (curl -sS -o $tmp -w "%{http_code}" -H "Content-Type: application/json" -d "$payload" "$URL")
  set rc $status
  set body (cat $tmp); rm -f $tmp
  if test $rc -ne 0
    echo (set_color red)"Transport error probing $URL (curl rc=$rc)."(set_color normal) >&2
    return 1
  end
  if test "$code" != "200"
    echo (set_color red)"HTTP $code from $URL"(set_color normal) >&2
    echo $body >&2
    return 1
  end
  set seq (printf "%s" $body | jq -r '.result // empty' 2>/dev/null)
  if test -z "$seq"
    echo (set_color red)"No result from RPC probe at $URL."(set_color normal) >&2
    return 1
  end
  echo "Sui RPC OK: latest checkpoint seq=$seq"
end

### --------- main workflow ----------
function suiwallet_bootstrap --description "Interactive setup of a Sui wallet pod with PVC; creates address and prints recovery phrase"
  _need kubectl jq curl awk; or return 1

  _banner "Sui wallet bootstrap"

  # --- Namespace
  read -P "Namespace [crypto]: " ns_raw
  if test -z "$ns_raw"; set ns_raw crypto; end
  set ns (_k8s_name $ns_raw)
  _require "Namespace" $ns; or return 1

  echo "Ensuring namespace '$ns' exists…"
  if kubectl get ns $ns >/dev/null 2>&1
    echo "Namespace $ns already exists."
  else
    kubectl create ns $ns; or return 1
    echo "Created namespace $ns."
  end

  # --- StorageClass
  kubectl get storageclass
  echo "TIP: Prefer a class with reclaimPolicy=Retain so a PVC delete won't delete the PV."
  set sc (_choose_sc); or return 1

  # --- Unified name (prefix wallet-sui-)
  read -P "Wallet name (no spaces, e.g. 'brad', base will be wallet-sui-brad): " wallet_raw
  _require "Wallet name" $wallet_raw; or return 1
  if string match -rq '\s' -- $wallet_raw
    echo (set_color red)"Error:"(set_color normal)" Wallet name cannot contain spaces." >&2
    return 1
  end
  set base (_k8s_name $wallet_raw)
  set base (string replace -r '^wallet-sui-' '' -- $base)
  set name "wallet-sui-$base"

  # Bind all k8s object names to the unified base
  set pvc_name $name
  set app_name $name

  # --- Detect existing resources (idempotence)
  set exists_any 0
  set found_list
  for r in "deploy/$app_name" (printf "netpol/%s-deny-ingress" $app_name)
    if kubectl -n $ns get $r >/dev/null 2>&1
      set -a found_list $r
      set exists_any 1
    end
  end
  if kubectl -n $ns get pvc $pvc_name >/dev/null 2>&1
    set -a found_list "pvc/$pvc_name"
    set exists_any 1
  end
  if kubectl -n $ns get secret (printf "%s-mnemonic" $app_name) >/dev/null 2>&1
    set -a found_list (printf "secret/%s-mnemonic" $app_name)
    set exists_any 1
  end
  if test $exists_any -eq 1
    _banner "Existing resources detected for $name"
    for r in $found_list
      echo "  - $ns/$r"
    end
    read -P "Remove EVERYTHING (deploy/netpol/PVC/secret) and recreate? (y/N): " wipe
    if string match -qi 'y*' -- $wipe
      kubectl -n $ns delete deploy $app_name --ignore-not-found --wait=true >/dev/null 2>&1; or true
      kubectl -n $ns delete netpol (printf "%s-deny-ingress" $app_name) --ignore-not-found --wait=true >/dev/null 2>&1; or true
      kubectl -n $ns delete pvc $pvc_name --ignore-not-found --wait=true >/dev/null 2>&1; or true
      kubectl -n $ns delete secret (printf "%s-mnemonic" $app_name) --ignore-not-found >/dev/null 2>&1; or true
      echo "Cleaned up previous resources."
    else
      echo "Reusing existing resources; they will be applied in-place."
    end
  end

  # --- Node scheduling (worker-only by default)
  read -P "Schedule only on worker nodes? (y/N) [y]: " pin_workers
  if test -z "$pin_workers"; set pin_workers y; end
  set use_pin 0
  if string match -qi 'y*' -- $pin_workers
    set use_pin 1
    read -P "Worker label key [node-role.kubernetes.io/worker]: " node_label_key
    if test -z "$node_label_key"; set node_label_key node-role.kubernetes.io/worker; end
    read -P "Worker label value [true]: " node_label_val
    if test -z "$node_label_val"; set node_label_val true; end
  end

  # --- Network and RPC
  read -P "Network [mainnet|testnet|devnet] [mainnet]: " net
  if test -z "$net"; set net mainnet; end
  switch $net
    case mainnet
      set rpc_url https://fullnode.mainnet.sui.io:443
    case testnet
      set rpc_url https://fullnode.testnet.sui.io:443
    case devnet
      set rpc_url https://fullnode.devnet.sui.io:443
    case '*'
      echo (set_color red)"Error:"(set_color normal)" network must be mainnet|testnet|devnet"; return 1
  end

  _banner "Probing Sui RPC endpoint"
  if not _probe_sui_rpc $rpc_url
    echo (set_color red)"Aborting due to RPC probe failure."(set_color normal)
    return 1
  end

  # --- Image and address alias
  set image_default (_sui_default_image $net)
  echo "NOTE: Prefer a multi-arch image you built (see instructions below)."
  read -P "Container image [$image_default]: " image
  if test -z "$image"; set image $image_default; end

  read -P "Address alias to create [main]: " alias
  if test -z "$alias"; set alias main; end

  read -P "Mnemonic word length [24]: " wl
  if test -z "$wl"; set wl 24; end

  read -P "Store mnemonic as a Kubernetes Secret? (NOT recommended) (y/N): " store_mn
  set store_mn (string lower -- $store_mn)

  # --- Optional NetworkPolicy
  read -P "Add NetworkPolicy (deny all ingress; allow egress) ? (y/N): " want_np
  set want_np (string lower -- $want_np)

  _banner "Summary"
  echo "  Namespace:     $ns"
  echo "  StorageClass:  $sc"
  echo "  Base name:     $name"
  echo "  PVC:           $pvc_name"
  echo "  App/Deployment:$app_name"
  echo "  Image:         $image"
  echo "  Network:       $net"
  echo "  RPC URL:       $rpc_url"
  echo "  New alias:     $alias  (word length: $wl)"
  if test $use_pin -eq 1
    echo "  NodeSelector:  $node_label_key=$node_label_val"
  end
  if string match -qi 'y*' -- $want_np
    echo "  NetworkPolicy: deny-all ingress (egress allowed)"
  end
  read -P "Proceed? [y/N]: " proceed
  if not string match -qi 'y*' -- $proceed
    echo (set_color yellow)"Aborted by user at confirmation step."(set_color normal)
    return 1
  end

  _banner "Applying PVC"
  if kubectl -n $ns get pvc $pvc_name >/dev/null 2>&1
    echo "PVC $ns/$pvc_name exists; keeping as-is."
  else
    set pvcfile (mktemp -t $pvc_name-pvc.XXXX.yaml)
    begin
      echo "apiVersion: v1"
      echo "kind: PersistentVolumeClaim"
      echo "metadata:"
      echo "  name: $pvc_name"
      echo "  namespace: $ns"
      echo "spec:"
      echo "  accessModes: [\"ReadWriteOnce\"]"
      echo "  storageClassName: $sc"
      echo "  resources:"
      echo "    requests:"
      echo "      storage: 1Gi"
    end > $pvcfile
    echo "--- PVC manifest ($pvcfile) ---"
    cat $pvcfile
    kubectl apply -f $pvcfile; or return 1
  end

  _banner "Applying Deployment"
  set dply (mktemp -t $app_name-deploy.XXXX.yaml)
  begin
    echo "apiVersion: apps/v1"
    echo "kind: Deployment"
    echo "metadata:"
    echo "  name: $app_name"
    echo "  namespace: $ns"
    echo "  labels: { app: $app_name }"
    echo "spec:"
    echo "  replicas: 1"
    echo "  strategy: { type: Recreate }"
    echo "  selector: { matchLabels: { app: $app_name } }"
    echo "  template:"
    echo "    metadata:"
    echo "      labels: { app: $app_name }"
    echo "    spec:"
    if test $use_pin -eq 1
      echo "      nodeSelector:"
      echo "        $node_label_key: \"$node_label_val\""
    end
    echo "      securityContext:"
    echo "        fsGroup: 1000"
    echo "        fsGroupChangePolicy: OnRootMismatch"
    echo "      initContainers:"
    echo "      - name: volume-permissions"
    echo "        image: busybox:1.36"
    echo "        command: [\"/bin/sh\",\"-lc\",\"mkdir -p /home/sui/.sui/sui_config && chown -R 1000:1000 /home/sui/.sui && chmod -R 0770 /home/sui/.sui\"]"
    echo "        securityContext: { runAsUser: 0 }"
    echo "        volumeMounts: [ { name: data, mountPath: /home/sui/.sui } ]"
    echo "      containers:"
    echo "      - name: sui-tools"
    echo "        image: $image"
    echo "        imagePullPolicy: IfNotPresent"
    echo "        command: [\"/bin/sh\",\"-lc\"]"
    echo "        args:"
    echo "          - |"
    echo "            # keep container ready for execs"
    echo "            sleep infinity"
    echo "        volumeMounts:"
    echo "        - name: data"
    echo "          mountPath: /home/sui/.sui"
    echo "        resources:"
    echo "          requests: { cpu: \"50m\", memory: \"128Mi\" }"
    echo "          limits:   { cpu: \"1\",   memory: \"512Mi\" }"
    echo "      volumes:"
    echo "      - name: data"
    echo "        persistentVolumeClaim: { claimName: $pvc_name }"
  end > $dply
  echo "--- Deployment manifest ($dply) ---"
  head -n 70 $dply
  echo "..."
  kubectl apply -f $dply; or return 1

  if string match -qi 'y*' -- $want_np
    _banner "Applying NetworkPolicy (deny-all ingress; allow all egress)"
    set np (mktemp -t $app_name-netpol.XXXX.yaml)
    begin
      echo "apiVersion: networking.k8s.io/v1"
      echo "kind: NetworkPolicy"
      echo "metadata:"
      printf "  name: %s-deny-ingress\n" $app_name
      echo "  namespace: $ns"
      echo "spec:"
      echo "  podSelector: { matchLabels: { app: $app_name } }"
      echo "  policyTypes: [\"Ingress\",\"Egress\"]"
      echo "  ingress: []"
      echo "  egress:"
      echo "  - {}"
    end > $np
    echo "--- NetworkPolicy manifest ($np) ---"
    cat $np
    kubectl apply -f $np; or return 1
  end

  _banner "Waiting for rollout"
  if not kubectl -n $ns rollout status deploy/$app_name --timeout=300s
    echo (set_color red)"Rollout did not finish in time. Recent events:"(set_color normal) >&2
    kubectl -n $ns get events --sort-by=.lastTimestamp | tail -n 40
    return 1
  end

  _banner "Validating Sui CLI inside the pod"
  set ARCH (kubectl -n $ns exec deploy/$app_name -- sh -lc 'uname -m' 2>/dev/null)
  set GLIBC (kubectl -n $ns exec deploy/$app_name -- sh -lc 'ldd --version 2>&1 | head -n1 || true' 2>/dev/null)
  set SUIV  (kubectl -n $ns exec deploy/$app_name -- sh -lc 'sui --version 2>&1 || true' 2>/dev/null)
  echo "Node arch: $ARCH"
  echo "GLIBC:    $GLIBC"
  echo "sui:      $SUIV"

  if test -z "$SUIV"; or string match -q "*not found*" -- $SUIV
    echo (set_color red)"Error:"(set_color normal)" 'sui' did not run inside the pod."
    echo "If you see GLIBC < 2.38 here, rebuild the image on Ubuntu 24.04 as shown in section A."
    return 1
  end

  _banner "Initializing Sui client env ($net) and creating a new address"
  # Create/switch env, then create a new address with alias.
  # Try JSON first; fall back to parsing text.
  set TMP (mktemp)

  # Ensure config dir exists (inside the pod) and env points to your chosen RPC.
  kubectl -n $ns exec deploy/$app_name -- sh -lc \
    (printf 'mkdir -p /home/sui/.sui/sui_config ;
             sui client new-env --alias %s --rpc %s >/dev/null 2>&1 || true ;
             sui client switch --env %s >/dev/null 2>&1 || true' $net $rpc_url $net)

  # Try JSON (preferred)
  set JSON (kubectl -n $ns exec deploy/$app_name -- sh -lc \
    (printf 'sui client new-address ed25519 --word-length %s --alias %s --json 2>/dev/null || true' $wl $alias))

  set MN   (printf "%s" $JSON | jq -r '.secretRecoveryPhrase // .mnemonic // .mnemonicPhrase // empty' 2>/dev/null)
  set ADDR (printf "%s" $JSON | jq -r '.address // empty' 2>/dev/null)

  if test -n "$MN"
    kubectl -n $ns logs deploy/$app_name --since=10s >/dev/null 2>&1 || true
    kubectl -n $ns exec deploy/$app_name -- sh -lc \
      (printf 'echo "SECRET RECOVERY PHRASE: %s" >> /home/sui/README_MNEMONIC && chmod 0600 /home/sui/README_MNEMONIC' "$MN")
  end

  if test -z "$MN" -o -z "$ADDR"
    # Fall back to plain text (robust across CLI changes)
    kubectl -n $ns exec deploy/$app_name -- sh -lc \
      (printf 'sui client new-address ed25519 --word-length %s --alias %s 2>&1 || true' $wl $alias) | tee $TMP >/dev/null

    if test -z "$MN"
      # Usually phrase is printed on the line right after the "Secret Recovery Phrase" header
      set MN (awk '/Secret Recovery Phrase/ {getline; print; exit}' $TMP)
    end
    if test -z "$ADDR"
      # Typical line: "Address: 0xabc..."; extract the RHS
      set ADDR (awk -F': ' '/^Address:/ {print $2; exit}' $TMP)
    end
  end

  # Make the generated address active (address wins; alias as backup)
  if test -n "$ADDR"
    kubectl -n $ns exec deploy/$app_name -- sh -lc (printf 'sui client switch --address %s >/dev/null 2>&1 || true' $ADDR)
  else
    kubectl -n $ns exec deploy/$app_name -- sh -lc (printf 'sui client switch --alias %s >/dev/null 2>&1 || true' $alias)
  end

  echo
  echo (set_color yellow)"IMPORTANT — Secret Recovery Phrase (write down & store offline):"(set_color normal)
  if test -n "$MN"
    echo $MN
  else
    echo "(mnemonic not detected — check 'kubectl -n $ns logs deploy/$app_name' output)"
  end
  echo
  echo "Address alias '$alias' appears to be: $ADDR"

  # Optional: store mnemonic in a Secret (not recommended)
  if test "$store_mn" = "y" -o "$store_mn" = "yes"
    if test -n "$MN"
      kubectl -n $ns create secret generic "$app_name-mnemonic" \
        --from-literal=mnemonic="$MN" --dry-run=client -o yaml | kubectl -n $ns apply -f -
      echo (set_color yellow)"Stored mnemonic in Secret $ns/{$app_name}-mnemonic. Treat your cluster as sensitive."(set_color normal)
    else
      echo (set_color red)"Warning:"(set_color normal)" mnemonic empty; not storing."
    end
  end

  echo
  echo "Done. Files inside the pod:"
  kubectl -n $ns exec deploy/$app_name -- sh -lc 'ls -l /home/sui/.sui/sui_config || true'
  echo
  echo "Useful commands:"
  echo "  suiwallet_addresses        $ns $app_name"
  echo "  suiwallet_gas              $ns $app_name"
  echo "  suiwallet_export_keystore  $ns $app_name  ./sui.keystore.$base"
  echo "  suiwallet_metrics          $ns $app_name  $base"
  echo "  kubectl -n $ns exec -it deploy/$app_name -- sh     # interactive CLI"
end

### --------- utilities ----------
function suiwallet_status -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  kubectl -n $NS get deploy,po,pvc,netpol -l app=$APP -o wide
end

function suiwallet_logs -a NS APP LINES
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  if test -z "$LINES"; set LINES 200; end
  kubectl -n $NS logs deploy/$APP --tail=$LINES
end

function suiwallet_wallet_ls -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  echo "Listing /home/sui/.sui/sui_config in $NS/$APP…" >&2
  kubectl -n $NS exec deploy/$APP -- sh -lc 'ls -la /home/sui/.sui/sui_config || true'
end

function suiwallet_addresses -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client addresses || true'
end

function suiwallet_export_keystore -a NS APP DEST
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  if test -z "$DEST"; set DEST ./sui.keystore; end
  set POD (kubectl -n $NS get pod -l app=$APP -o jsonpath='{.items[0].metadata.name}' 2>/dev/null)
  if test -z "$POD"
    echo (set_color red)"Error:"(set_color normal)" no pod found for app=$APP in ns=$NS" >&2
    return 1
  end
  echo "Copying keystore from $POD to $DEST (keep it safe!)"
  kubectl -n $NS cp $POD:/home/sui/.sui/sui_config/sui.keystore $DEST
end

# Summarize gas coins and total balance; tolerant to schema differences
function suiwallet_gas -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
  if test -z "$J"
    echo "No JSON from 'sui client gas' (is the address set and env working?)" >&2
    return 1
  end
  set NUM (printf "%s" $J | jq -r '[.. | .gasObjects? // empty | length] | add // 0')
  if test -z "$NUM" -o "$NUM" = "null"
    set NUM (printf "%s" $J | jq -r '[.. | .coins? // empty | length] | add // 0')
  end
  set SUM (printf "%s" $J | jq -r '
    (.. | .totalBalance? // empty) as $t
    | if $t != null then ($t|tonumber)
      else [.. | .gasObjects? // empty | .[]? | .balance? | tonumber] | add
    end // 0
  ')
  # Convert Mist -> SUI using python -c
  set SUM_SUI (python3 -c 'from decimal import Decimal; import sys; q=Decimal(sys.argv[1]) if sys.argv[1] else Decimal(0); print((q/Decimal("1e9")).quantize(Decimal("0.000000001")))' -- $SUM)
  echo "Gas coins: $NUM    Total: $SUM ($SUM_SUI SUI)"
end

# Wait until balance >= threshold (SUI), timeout seconds
function suiwallet_wait_balance -a NS APP MIN_SUI TIMEOUT
  _need python3; or return 1
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  if test -z "$MIN_SUI"; set MIN_SUI 0; end
  if test -z "$TIMEOUT"; set TIMEOUT 300; end
  set start (date +%s)
  while true
    set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
    set SUM (printf "%s" $J | jq -r '
      (.. | .totalBalance? // empty) as $t
      | if $t != null then ($t|tonumber)
        else [.. | .gasObjects? // empty | .[]? | .balance? | tonumber] | add
      end // 0
    ')
    set SUM_SUI (python3 -c 'from decimal import Decimal; import sys; q=Decimal(sys.argv[1]) if sys.argv[1] else Decimal(0); print(q/Decimal("1e9"))' -- $SUM)
    set ge (python3 -c 'from decimal import Decimal; import sys; print(1 if Decimal(sys.argv[1]) >= Decimal(sys.argv[2]) else 0)' -- $SUM_SUI $MIN_SUI)
    if test "$ge" = "1"
      echo "Balance ready: $SUM_SUI SUI (>= $MIN_SUI)"
      return 0
    end
    if test (math (date +%s) - $start) -ge $TIMEOUT
      echo "Timed out waiting for balance >= $MIN_SUI SUI (current $SUM_SUI SUI)."
      return 1
    end
    sleep 6
  end
end

# Send SUI using `transfer-sui` picking the largest coin
# Usage: suiwallet_transfer_sui [ns] [app] <to_addr> <amount_sui> [gas_budget_mist=10000000]
function suiwallet_transfer_sui -a NS APP TO AMT_SUI GAS_BUDGET
  _need jq python3; or return 1
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  if test -z "$TO" -o -z "$AMT_SUI"
    echo "Usage: suiwallet_transfer_sui [ns] [app] <to_address> <amount_sui> [gas_budget_mist]" >&2
    return 1
  end
  if test -z "$GAS_BUDGET"; set GAS_BUDGET 10000000; end

  set AMT_MIST (python3 -c 'from decimal import Decimal; import sys; print(int((Decimal(sys.argv[1])*Decimal("1e9")).to_integral_value()))' -- $AMT_SUI)
  set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
  set COIN (printf "%s" $J | jq -r '
    ([.. | .gasObjects? // empty | .[]?] // [])
    | sort_by(.balance|tonumber) | last | .coinObjectId // empty
  ')
  if test -z "$COIN"
    echo (set_color red)"No gas coins found to send from."(set_color normal) >&2
    return 1
  end

  echo "Using coin: $COIN"
  kubectl -n $NS exec deploy/$APP -- sh -lc \
    (printf 'sui client transfer-sui --to %s --sui-coin-object-id %s --amount %s --gas-budget %s' $TO $COIN $AMT_MIST $GAS_BUDGET)
end

# Merge all gas coins into the largest one
function suiwallet_merge_gas -a NS APP
  _need jq; or return 1
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
  set IDS (printf "%s" $J | jq -r '([.. | .gasObjects? // empty | .[]?] // []) | sort_by(.balance|tonumber) | reverse | .[].coinObjectId')
  set coins $IDS
  if test (count $coins) -lt 2
    echo "Nothing to merge (need >=2 gas coins)."
    return 0
  end
  set primary $coins[1]
  for i in (seq 2 (count $coins))
    set c $coins[$i]
    echo "Merging $c -> $primary"
    kubectl -n $NS exec deploy/$APP -- sh -lc (printf 'sui client merge-coin --primary-coin %s --coin-to-merge %s --gas-budget 10000000' $primary $c)
  end
end

# Restore an address from a Secret Recovery Phrase into the running pod
# Usage: suiwallet_restore [ns] [app] [alias] [network=mainnet]
function suiwallet_restore -a NS APP ALIAS NET
  _need kubectl jq; or return 1
  if test -z "$NS";  set NS  crypto;   end
  if test -z "$APP"; set APP wallet-sui-main; end
  if test -z "$ALIAS"; set ALIAS restored; end
  if test -z "$NET"; set NET mainnet; end

  switch $NET
    case mainnet
      set RPC https://fullnode.mainnet.sui.io:443
    case testnet
      set RPC https://fullnode.testnet.sui.io:443
    case devnet
      set RPC https://fullnode.devnet.sui.io:443
    case '*'
      echo (set_color red)"Error:"(set_color normal)" NET must be mainnet|testnet|devnet"; return 1
  end

  echo (set_color yellow)"Paste your 12/24-word Sui Secret Recovery Phrase (input hidden):"(set_color normal)
  read -s MNEMONIC
  echo
  if test -z "$MNEMONIC"
    echo (set_color red)"Error:"(set_color normal)" empty mnemonic."; return 1
  end

  # Ensure env is configured and active
  kubectl -n $NS exec deploy/$APP -- sh -lc \
    (printf 'mkdir -p /home/sui/.sui/sui_config ;
             sui client new-env --alias %s --rpc %s >/dev/null 2>&1 || true ;
             sui client switch --env %s >/dev/null 2>&1 || true' $NET $RPC $NET); or return 1

  # Import mnemonic into keystore (non-interactive; enter scheme then phrase)
  # keytool is interactive; we feed "ed25519" then the phrase via stdin.
  set TMP (mktemp)
  printf "ed25519\n%s\n" "$MNEMONIC" \
  | kubectl -n $NS exec -i deploy/$APP -- sh -lc 'sui keytool import 2>&1' \
  | tee $TMP >/dev/null

  # Create a named alias pointing to one of the imported keys by re-using new-address --recover
  # (new-address --recover will prompt for phrase; we feed it again to bind an alias)
  set OUT (mktemp)
  printf "%s\n" "$MNEMONIC" \
  | kubectl -n $NS exec -i deploy/$APP -- sh -lc \
      (printf 'sui client new-address ed25519 --alias %s --recover 2>&1' $ALIAS) \
  | tee $OUT >/dev/null

  # Try to extract the resulting address
  set ADDR (awk -F': ' '/^Address:/ {print $2; exit}' $OUT)
  if test -z "$ADDR"
    # fallback: pick the address for the alias from the address table
    set ADDR (kubectl -n $NS exec deploy/$APP -- sh -lc (printf 'sui client addresses | awk "/ %s\\s*$/ {print \\$NF}" | tail -n1' $ALIAS) 2>/dev/null)
  end

  echo
  echo "Restored alias: $ALIAS"
  echo "Address:       $ADDR"
  echo (set_color yellow)"IMPORTANT:"(set_color normal)" store your recovery phrase offline. Do NOT keep it in the cluster."

  # Make it active for the client
  if test -n "$ADDR"
    kubectl -n $NS exec deploy/$APP -- sh -lc (printf 'sui client switch --address %s >/dev/null 2>&1 || true' $ADDR)
  end
end

function suiwallet_stop -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  kubectl -n $NS delete deploy $APP --ignore-not-found
  echo "Stopped $NS/$APP. PVC retained."
end

# Print the primary (first) address by alias search
function suiwallet_primary_address -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  kubectl -n $NS exec deploy/$APP -- sh -lc \
    "sui client addresses | awk 'NF{print \$NF}' | head -n1" 2>/dev/null
end

# Quick overview
function suiwallet_overview -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  echo "== Sui wallet overview (ns=$NS app=$APP)"
  kubectl -n $NS exec deploy/$APP -- sh -lc 'echo "-- Addresses:"; sui client addresses || true'
  kubectl -n $NS exec deploy/$APP -- sh -lc 'echo "-- Gas objects:"; sui client gas 2>/dev/null || true'
end

# Sui keystore size (for Grafana/Prometheus)
function suiwallet_keystore_size_bytes -a NS APP
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  set SZ (kubectl -n $NS exec deploy/$APP -- sh -lc \
    'test -e /home/sui/.sui/sui_config/sui.keystore && stat -c %s /home/sui/.sui/sui_config/sui.keystore || echo 0' 2>/dev/null)
  echo $SZ
end

# Prometheus-friendly one-liner metric
# Example usage: suiwallet_metrics crypto wallet-sui-test mywallet
function suiwallet_metrics -a NS APP WALLET_NAME
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  if test -z "$WALLET_NAME"; set WALLET_NAME main; end
  set BYTES (suiwallet_keystore_size_bytes $NS $APP)
  printf "wallet_size_bytes{chain=\"sui\",namespace=\"%s\",app=\"%s\",wallet=\"%s\"} %s\n" $NS $APP $WALLET_NAME $BYTES
end

function suiwallet_purge -a NS APP PVC
  if test -z "$NS"; set NS crypto; end
  if test -z "$APP"; set APP wallet-sui-main; end
  if test -z "$PVC"; set PVC $APP; end
  echo "Type to confirm: PURGE $NS $PVC"
  read CONFIRM
  if test "$CONFIRM" != "PURGE $NS $PVC"
    echo "Aborted."
    return 1
  end
  kubectl -n $NS delete deploy $APP --ignore-not-found
  kubectl -n $NS delete pvc $PVC --ignore-not-found --wait=true
  kubectl -n $NS delete netpol (printf "%s-deny-ingress" $APP) --ignore-not-found >/dev/null 2>&1
  echo "Purged. Ensure you have the mnemonic backed up if you ever need to restore."
end

function suiwallet_help
  echo "suiwallet_bootstrap                # interactive deploy + PVC + optional NP; creates env+address, prints mnemonic"
  echo "suiwallet_status [ns] [app]        # show deploy/pods/pvc/netpol"
  echo "suiwallet_logs   [ns] [app] [N]    # tail N (default 200) lines of pod logs"
  echo "suiwallet_wallet_ls [ns] [app]     # list ~/.sui/sui_config inside pod"
  echo "suiwallet_addresses [ns] [app]     # list addresses"
  echo "suiwallet_gas [ns] [app]           # summarize gas coins and total (Mist & SUI)"
  echo "suiwallet_wait_balance [ns] [app] <min_sui> [timeout_s=300]"
  echo "suiwallet_transfer_sui [ns] [app] <to> <amount_sui> [gas_budget_mist]"
  echo "suiwallet_merge_gas [ns] [app]     # merge many gas coins into one"
  echo "suiwallet_export_keystore [ns] [app] [dest=./sui.keystore]"
  echo "suiwallet_metrics [ns] [app] [walletname]  # Prometheus line: wallet_size_bytes{chain=\"sui\",...}"
  echo "suiwallet_stop  [ns] [app]         # delete deployment (keep PVC)"
  echo "suiwallet_purge [ns] [app] [pvc]   # delete deployment + PVC (danger!)"
end
