#!/usr/bin/env bash
#
# secret-input.sh — общий хелпер для работы с k8s Secret klvd-node.
# Source'ится:
#   - helm/scripts/gen-secrets.sh            (только секрет/ротация)
#   - klavdii-installer/klvd-install-helm.sh (секрет + helm install)
#
# Содержит:
#   * примитивы вывода/промптов (g_*) — gum если $GUM executable, иначе fallback на read;
#   * secret_resolve(ns, default_name) — 3 режима ввода секрета на выбор администратора:
#         existing  — указать имя уже созданного Secret
#         files     — 4 файла на диске (pg_user, pg_password, klvd_key, ssl_cert)
#         generate  — интерактивный ввод/генерация (self-signed ssl_cert, rand klvd_key)
#     Возвращает (echo) имя Secret для использования в values.secrets.existingSecret.
#
# Контракт Secret (file-based /run/secrets, как docker-compose installer'а):
#   ключи: pg_user, pg_password, klvd_key, ssl_cert
#   ssl_cert = cert+key PEM в одном файле (cat cert.pem key.pem).
#
# НЕ запускать напрямую — source. GUM может быть задан вызывающим (klvd-install-helm.sh
# скачивает gum как install.sh); без GUM — fallback на read.
#

# ── примитивы ──────────────────────────────────────────────────────────────────
# Статус-сообщения — в stderr (stdout отдан под возвращаемые данные: имя Secret / манифест).
si_log()  { printf '\033[1;34m[klvd]\033[0m %s\n' "$*" >&2; }
si_warn() { printf '\033[1;33m[!]\033[0m %s\n' "$*" >&2; }
si_err()  { printf '\033[1;31m[x]\033[0m %s\n' "$*" >&2; }
si_die()  { si_err "$*"; exit 1; }
si_ok()   { printf '\033[1;32m[✓]\033[0m %s\n' "$*" >&2; }

si_g_header() {
    if [[ -x "${GUM:-}" ]]; then
        "$GUM" style --border rounded --padding "0 2" --border-foreground 4 --bold "$1" >&2
    else
        printf '\n=== %s ===\n' "$1" >&2
    fi
}
si_g_input() {
    local label="$1" def="${2:-}" out=""
    if [[ -x "${GUM:-}" ]]; then
        local args=(--prompt "› " --header "$label" --placeholder "введите и нажмите Enter…")
        [[ -n "$def" ]] && args+=(--value "$def")
        if out="$("$GUM" input "${args[@]}" 2>/dev/null)"; then out="${out:-$def}"; else out="$def"; fi
    else
        local ans; read -r -p "$label${def:+ [$def]}: " ans || ans=""
        out="${ans:-$def}"
    fi
    printf '%s\n' "$out"
}
si_g_password() {
    local label="$1" out=""
    if [[ -x "${GUM:-}" ]]; then
        if out="$("$GUM" input --prompt "🔒 " --header "$label" --placeholder "ввод скрыт…" --password 2>/dev/null)"; then :; else out=""; fi
    else
        local ans; read -rs -p "$label: " ans; echo >&2; out="$ans"
    fi
    printf '%s\n' "$out"
}
si_g_confirm() {
    local q="$1" def="${2:-true}" hint
    [[ "$def" == true ]] && hint="Y/n" || hint="y/N"
    if [[ -x "${GUM:-}" ]]; then
        "$GUM" confirm --default="$def" "$q" 2>/dev/null
    else
        local ans; read -r -p "$q [$hint] " ans || ans=""
        { [[ "$def" == true && -z "$ans" ]] || [[ "$ans" =~ ^[Yy] ]]; }
    fi
}
si_g_choose() {  # single: si_g_choose "header" "val1|label1" "val2|label2" ...
    local header="$1"; shift
    local items=("$@") label value opts=()
    for it in "${items[@]}"; do value="${it%%|*}"; label="${it#*|}"; opts+=("$label [$value]"); done
    if [[ -x "${GUM:-}" ]]; then
        local sel
        sel="$("$GUM" choose --header "$header" --selected-prefix "✓ " --unselected-prefix "  " "${opts[@]}" 2>/dev/null)" \
            || { printf '%s\n' "${items[0]%%|*}"; return; }
        printf '%s' "$sel" | sed -E 's/^.*\[([^][]+)]$/\1/'
    else
        local i=1; printf '\n%s\n' "$header" >&2
        for it in "${items[@]}"; do value="${it%%|*}"; label="${it#*|}"; printf '  %d) %s [%s]\n' "$i" "$label" "$value" >&2; ((i++)); done
        local ans; read -r -p "номер: " ans || ans="1"
        [[ "$ans" =~ ^[0-9]+$ ]] && ((ans>=1 && ans<=${#items[@]})) || ans=1
        printf '%s\n' "${items[$((ans-1))]%%|*}"
    fi
}

# ── kubectl ────────────────────────────────────────────────────────────────────
si_kubectl() { command -v kubectl >/dev/null || si_die "kubectl не найден в PATH."; kubectl "$@"; }

si_secret_exists() {  # ns name → 0 если есть
    si_kubectl -n "$1" get secret "$2" >/dev/null 2>&1
}

# ── генерация self-signed ssl_cert (cert+key PEM в одном файле), как install.sh ─
si_gen_ssl_cert() {  # outfile
    local out="$1" tdir
    tdir="$(mktemp -d)"
    openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
        -keyout "$tdir/key.pem" -out "$tdir/cert.pem" \
        -subj "/CN=klvd-wui" 2>/dev/null \
        || si_die "openssl не удалось сгенерировать ssl_cert."
    cat "$tdir/cert.pem" "$tdir/key.pem" > "$out"
    rm -rf "$tdir"
    chmod 600 "$out"
}

# ── применение Secret из 4 файлов ──────────────────────────────────────────────
# $1 ns  $2 name  $3 pg_user_file  $4 pg_password_file  $5 klvd_key_file  $6 ssl_cert_file
si_apply_secret_from_files() {
    local ns="$1" name="$2" fu="$3" fp="$4" fk="$5" fc="$6"
    [[ -s "$fu" ]] || si_die "pg_user файл пуст/нет: $fu"
    [[ -s "$fp" ]] || si_die "pg_password файл пуст/нет: $fp"
    [[ -s "$fk" ]] || si_die "klvd_key файл пуст/нет: $fk"
    [[ -s "$fc" ]] || si_die "ssl_cert файл пуст/нет: $fc"
    si_log "Применяется Secret $name (namespace $ns)…"
    si_secret_exists "$ns" "$name" && si_kubectl -n "$ns" delete secret "$name" >/dev/null
    si_kubectl -n "$ns" create secret generic "$name" \
        --from-file=pg_user="$fu" \
        --from-file=pg_password="$fp" \
        --from-file=klvd_key="$fk" \
        --from-file=ssl_cert="$fc" \
        >/dev/null || si_die "kubectl create secret не удался."
    si_ok "Secret $name создан (4 ключа: pg_user, pg_password, klvd_key, ssl_cert)."
}

# ── главный: выбор режима + применение → echo имени Secret ─────────────────────
# $1 ns  $2 default_name  $3 pg_user_default(для generate)
# Возвращает имя через stdout (printf) — для вызова в $(...).
# Если установлена SI_QUIET_NAME=1 — имя НЕ печатается, а кладётся в глобал SI_SECRET_NAME
# (удобно для -o yaml, где stdout отдан под манифест).
secret_resolve() {
    local ns="$1" name="${2:-klvd-node-secrets}" pgdef="${3:-appuser}"
    local mode
    mode="$(si_g_choose "Способ указания секрета (pg_user, pg_password, klvd_key, ssl_cert)" \
        "existing|Указать существующий k8s Secret" \
        "files|Из файлов на диске (4 пути)" \
        "generate|Сгенерировать / ввести (self-signed ssl_cert, rand klvd_key)")"

    case "$mode" in
        existing)
            name="$(si_g_input "Имя существующего Secret в namespace $ns" "$name")"
            si_secret_exists "$ns" "$name" \
                || si_die "Secret $name не найден в namespace $ns. Создайте его или выберите другой режим."
            si_ok "Используется существующий Secret: $name"
            ;;
        files)
            name="$(si_g_input "Имя нового Secret" "$name")"
            local fu fp fk fc tdir
            tdir="$(mktemp -d)"
            fu="$(si_g_input "Файл pg_user" "")"
            fp="$(si_g_input "Файл pg_password" "")"
            fk="$(si_g_input "Файл klvd_key (master secret)" "")"
            fc="$(si_g_input "Файл ssl_cert (cert+key PEM)" "")"
            si_apply_secret_from_files "$ns" "$name" "$fu" "$fp" "$fk" "$fc"
            rm -rf "$tdir"
            ;;
        generate)
            name="$(si_g_input "Имя нового Secret" "$name")"
            local pg_user pg_password klvd_key ssl_cert_file gen_klvd
            pg_user="$(si_g_input "PostgreSQL user" "$pgdef")"
            pg_password="$(si_g_password "PostgreSQL password")"
            [[ -n "$pg_password" ]] || si_die "Пустой pg_password недопустим."
            gen_klvd="$(si_g_confirm "Сгенерировать klvd_key (openssl rand -hex 32)?" true)"
            if [[ "$gen_klvd" == true || -z "$gen_klvd" ]]; then
                klvd_key="$(openssl rand -hex 32 2>/dev/null)" || si_die "openssl rand не удался."
                si_ok "klvd_key сгенерирован."
            else
                klvd_key="$(si_g_password "klvd_key (master secret)")"
                [[ -n "$klvd_key" ]] || si_die "Пустой klvd_key недопустим."
            fi
            local tdir fu fp fk fc
            tdir="$(mktemp -d)"
            fu="$tdir/pg_user";     printf '%s' "$pg_user" > "$fu"
            fp="$tdir/pg_password";  printf '%s' "$pg_password" > "$fp"
            fk="$tdir/klvd_key";    printf '%s' "$klvd_key" > "$fk"
            fc="$tdir/ssl_cert"
            if si_g_confirm "Сгенерировать self-signed ssl_cert?" true; then
                si_gen_ssl_cert "$fc"
                si_ok "ssl_cert: self-signed (CN=klvd-wui, 365d)."
            else
                local certpath keypath
                certpath="$(si_g_input "Путь к cert PEM" "")"
                keypath="$(si_g_input "Путь к key PEM" "")"
                [[ -s "$certpath" && -s "$keypath" ]] || si_die "cert/key файлы не найдены."
                cat "$certpath" "$keypath" > "$fc"; chmod 600 "$fc"
            fi
            si_apply_secret_from_files "$ns" "$name" "$fu" "$fp" "$fk" "$fc"
            rm -rf "$tdir"
            ;;
        *) si_die "неизвестный режим секрета: $mode" ;;
    esac
    SI_SECRET_NAME="$name"
    if [[ -z "${SI_QUIET_NAME:-}" ]]; then printf '%s\n' "$name"; fi
}
