"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useMemo, useState, } from "react";
import { cn } from "@stigmer/theme";
import { getUserMessage } from "@stigmer/sdk";
import { useStigmer } from "../hooks";
import { toError } from "../internal/toError";
import { useUpdateEnvironmentVariables } from "./useUpdateEnvironmentVariables";
import { useRemoveEnvironmentVariables } from "./useRemoveEnvironmentVariables";
import { useRevealSecretValue } from "./useRevealSecretValue";
/**
 * Self-contained component that displays and manages all variables for
 * a single {@link Environment}. Fetches environment data by ID, renders
 * an editable variable list, and commits changes inline per variable.
 *
 * Each variable supports inline editing with immediate save, secret
 * value reveal (30 s auto-clear via `getSecretValue` RPC), and inline
 * delete confirmation. New variables are added via a collapsible form
 * at the bottom of the list.
 *
 * All visual properties flow through `--stgm-*` design tokens.
 *
 * Part of the **Environment Flow** — manages persistent credentials
 * stored in Environment resources.
 *
 * Platform builders who need a fully custom UI should use the Layer 1
 * hooks directly ({@link useUpdateEnvironmentVariables},
 * {@link useRemoveEnvironmentVariables}, {@link useRevealSecretValue}).
 *
 * @example
 * ```tsx
 * <EnvironmentVariableEditor environmentId="env-abc123" />
 *
 * <EnvironmentVariableEditor
 *   environmentId={env.metadata.id}
 *   readOnly
 *   className="mt-4"
 * />
 * ```
 */
export function EnvironmentVariableEditor({ environmentId, readOnly = false, onVariableUpdated, onVariableRemoved, className, }) {
    const stigmer = useStigmer();
    const { updateVariables } = useUpdateEnvironmentVariables();
    const { removeVariables } = useRemoveEnvironmentVariables();
    const [environment, setEnvironment] = useState(null);
    const [isLoading, setIsLoading] = useState(true);
    const [loadError, setLoadError] = useState(null);
    const [showAddForm, setShowAddForm] = useState(false);
    useEffect(() => {
        const cancelled = { current: false };
        setIsLoading(true);
        setLoadError(null);
        stigmer.environment.get(environmentId).then((result) => {
            if (cancelled.current)
                return;
            setEnvironment(result);
            setIsLoading(false);
        }, (err) => {
            if (cancelled.current)
                return;
            setLoadError(toError(err));
            setIsLoading(false);
        });
        return () => {
            cancelled.current = true;
        };
    }, [environmentId, stigmer]);
    const variables = useMemo(() => {
        const data = environment?.spec?.data ?? {};
        return Object.entries(data)
            .map(([key, val]) => ({
            key,
            value: val.value,
            isSecret: val.isSecret,
            description: val.description,
        }))
            .sort((a, b) => a.key.localeCompare(b.key));
    }, [environment]);
    const handleSave = useCallback(async (key, input) => {
        const updated = await updateVariables({
            environmentId,
            variables: { [key]: input },
        });
        setEnvironment(updated);
        onVariableUpdated?.(key);
    }, [environmentId, updateVariables, onVariableUpdated]);
    const handleRemove = useCallback(async (key) => {
        const updated = await removeVariables({
            environmentId,
            keys: [key],
        });
        setEnvironment(updated);
        onVariableRemoved?.(key);
    }, [environmentId, removeVariables, onVariableRemoved]);
    const handleAdd = useCallback(async (key, input) => {
        await handleSave(key, input);
        setShowAddForm(false);
    }, [handleSave]);
    if (isLoading) {
        return (_jsx("div", { className: cn("space-y-2", className), "aria-busy": "true", "aria-label": "Loading variables", children: Array.from({ length: 3 }, (_, i) => (_jsx("div", { className: "bg-muted-subtle h-8 animate-pulse rounded", style: { width: `${85 - i * 10}%` } }, i))) }));
    }
    if (loadError) {
        return (_jsx("p", { className: cn("text-destructive text-xs", className), role: "alert", children: getUserMessage(loadError) }));
    }
    return (_jsxs("div", { className: cn("space-y-1", className), children: [variables.length === 0 && !showAddForm ? (_jsx("p", { className: "text-muted-foreground py-4 text-center text-xs", children: "No variables configured." })) : (_jsx("div", { className: "divide-border/60 divide-y", role: "list", "aria-label": "Environment variables", children: variables.map((v) => (_jsx(VariableRow, { environmentId: environmentId, variable: v, readOnly: readOnly, onSave: handleSave, onDelete: handleRemove }, v.key))) })), !readOnly &&
                (showAddForm ? (_jsx(AddVariableForm, { onAdd: handleAdd, onCancel: () => setShowAddForm(false), existingKeys: variables.map((v) => v.key) })) : (_jsxs("button", { type: "button", onClick: () => setShowAddForm(true), className: cn("mt-1 flex items-center gap-1.5 rounded-md px-2 py-1.5 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "transition-colors"), children: [_jsx(PlusIcon, {}), "Add variable"] })))] }));
}
function VariableRow({ environmentId, variable, readOnly, onSave, onDelete, }) {
    const [mode, setMode] = useState("idle");
    const [editValue, setEditValue] = useState("");
    const [isSaving, setIsSaving] = useState(false);
    const [isDeleting, setIsDeleting] = useState(false);
    const [mutationError, setMutationError] = useState(null);
    const { reveal, revealedValue, isRevealing, error: revealError, clearRevealedValue, } = useRevealSecretValue();
    const error = mutationError ?? revealError;
    const startEdit = useCallback(() => {
        setEditValue(variable.isSecret ? "" : variable.value);
        setMode("editing");
        setMutationError(null);
    }, [variable.isSecret, variable.value]);
    const cancelEdit = useCallback(() => {
        setMode("idle");
        setEditValue("");
        setMutationError(null);
    }, []);
    const handleSave = useCallback(async () => {
        if (variable.isSecret && !editValue.trim())
            return;
        setIsSaving(true);
        setMutationError(null);
        try {
            await onSave(variable.key, {
                value: editValue,
                isSecret: variable.isSecret,
                description: variable.description || undefined,
            });
            setMode("idle");
            setEditValue("");
        }
        catch (err) {
            setMutationError(toError(err));
        }
        finally {
            setIsSaving(false);
        }
    }, [editValue, variable, onSave]);
    const requestDelete = useCallback(() => {
        setMode("confirming");
        setMutationError(null);
    }, []);
    const confirmDelete = useCallback(async () => {
        setIsDeleting(true);
        setMutationError(null);
        try {
            await onDelete(variable.key);
        }
        catch (err) {
            setMutationError(toError(err));
            setMode("idle");
        }
        finally {
            setIsDeleting(false);
        }
    }, [variable.key, onDelete]);
    const toggleReveal = useCallback(() => {
        if (revealedValue !== null) {
            clearRevealedValue();
        }
        else {
            reveal(environmentId, variable.key);
        }
    }, [environmentId, variable.key, reveal, revealedValue, clearRevealedValue]);
    const displayValue = variable.isSecret
        ? (revealedValue ?? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022")
        : (variable.value || "\u2014");
    // --- Edit mode ---
    if (mode === "editing") {
        return (_jsxs("div", { role: "listitem", children: [_jsxs("div", { className: "flex items-center gap-2 py-2", children: [_jsx("span", { className: "shrink-0 font-mono text-xs font-medium text-foreground", children: variable.key }), _jsx("input", { type: variable.isSecret ? "password" : "text", value: editValue, onChange: (e) => setEditValue(e.target.value), disabled: isSaving, placeholder: variable.isSecret ? "Enter new value" : "Value", autoFocus: true, className: cn("min-w-0 flex-1 rounded-md border border-input bg-background px-2 py-1 font-mono text-xs text-foreground", "placeholder:text-muted-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50"), onKeyDown: (e) => {
                                if (e.key === "Enter")
                                    handleSave();
                                if (e.key === "Escape")
                                    cancelEdit();
                            } }), _jsx(ActionButton, { onClick: handleSave, disabled: isSaving || (variable.isSecret && !editValue.trim()), label: "Save", variant: "primary", children: isSaving ? _jsx(SpinnerIcon, {}) : _jsx(CheckIcon, {}) }), _jsx(ActionButton, { onClick: cancelEdit, disabled: isSaving, label: "Cancel", variant: "muted", children: _jsx(XIcon, {}) })] }), _jsx(RowError, { error: error })] }));
    }
    // --- Idle / Confirming mode ---
    return (_jsxs("div", { role: "listitem", children: [_jsxs("div", { className: "group flex items-center gap-3 py-2", children: [_jsxs("div", { className: "flex shrink-0 items-baseline gap-1.5", children: [_jsx("span", { className: "font-mono text-xs font-medium text-foreground", title: variable.description || undefined, children: variable.key }), variable.isSecret && (_jsx("span", { className: "text-[0.55rem] uppercase tracking-wider text-muted-foreground-subtle", children: "secret" }))] }), _jsx("span", { className: cn("min-w-0 flex-1 truncate font-mono text-xs", variable.isSecret && revealedValue !== null
                            ? "text-foreground"
                            : "text-muted-foreground"), children: displayValue }), mode === "confirming" ? (_jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [_jsx("span", { className: "text-destructive text-[0.65rem]", children: "Delete?" }), _jsx(ActionButton, { onClick: confirmDelete, disabled: isDeleting, label: "Confirm delete", variant: "danger", children: isDeleting ? _jsx(SpinnerIcon, {}) : _jsx(CheckIcon, {}) }), _jsx(ActionButton, { onClick: () => setMode("idle"), label: "Cancel delete", variant: "muted", children: _jsx(XIcon, {}) })] })) : (!readOnly && (_jsxs("div", { className: "flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100", children: [variable.isSecret && (_jsx(ActionButton, { onClick: toggleReveal, disabled: isRevealing, label: revealedValue !== null
                                    ? `Hide ${variable.key}`
                                    : `Reveal ${variable.key}`, variant: "muted", children: isRevealing ? (_jsx(SpinnerIcon, {})) : revealedValue !== null ? (_jsx(EyeOffIcon, {})) : (_jsx(EyeIcon, {})) })), _jsx(ActionButton, { onClick: startEdit, label: `Edit ${variable.key}`, variant: "muted", children: _jsx(PencilIcon, {}) }), _jsx(ActionButton, { onClick: requestDelete, label: `Delete ${variable.key}`, variant: "muted-danger", children: _jsx(TrashIcon, {}) })] })))] }), _jsx(RowError, { error: error })] }));
}
// ---------------------------------------------------------------------------
// AddVariableForm
// ---------------------------------------------------------------------------
function AddVariableForm({ onAdd, onCancel, existingKeys, }) {
    const [key, setKey] = useState("");
    const [value, setValue] = useState("");
    const [isSecret, setIsSecret] = useState(false);
    const [isAdding, setIsAdding] = useState(false);
    const [error, setError] = useState(null);
    const trimmedKey = key.trim();
    const isDuplicate = existingKeys.includes(trimmedKey);
    const canSubmit = trimmedKey !== "" && !isAdding;
    const handleSubmit = useCallback(async (e) => {
        e.preventDefault();
        if (!canSubmit)
            return;
        setIsAdding(true);
        setError(null);
        try {
            await onAdd(trimmedKey, { value, isSecret });
        }
        catch (err) {
            setError(toError(err));
        }
        finally {
            setIsAdding(false);
        }
    }, [canSubmit, trimmedKey, value, isSecret, onAdd]);
    return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-2 pt-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: key, onChange: (e) => setKey(e.target.value), placeholder: "KEY", disabled: isAdding, autoFocus: true, className: cn("w-40 rounded-md border bg-background px-2 py-1 font-mono text-xs text-foreground", "placeholder:text-muted-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50", isDuplicate ? "border-amber-500/70" : "border-input") }), _jsx("input", { type: isSecret ? "password" : "text", value: value, onChange: (e) => setValue(e.target.value), placeholder: "Value", disabled: isAdding, className: cn("min-w-0 flex-1 rounded-md border border-input bg-background px-2 py-1 font-mono text-xs text-foreground", "placeholder:text-muted-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50"), onKeyDown: (e) => {
                            if (e.key === "Escape")
                                onCancel();
                        } }), _jsxs("label", { className: "flex shrink-0 cursor-pointer items-center gap-1 text-[0.65rem] text-muted-foreground select-none", children: [_jsx("input", { type: "checkbox", checked: isSecret, onChange: (e) => setIsSecret(e.target.checked), disabled: isAdding, className: "accent-primary size-3" }), "Secret"] })] }), isDuplicate && (_jsx("p", { className: "text-[0.65rem] text-amber-600 dark:text-amber-400", children: "This key already exists and will be overwritten." })), _jsx(RowError, { error: error }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "submit", disabled: !canSubmit, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1 text-xs font-medium", "bg-primary text-primary-foreground hover:bg-primary-hover", "disabled:pointer-events-none disabled:opacity-40"), children: [isAdding && _jsx(SpinnerIcon, {}), "Add"] }), _jsx("button", { type: "button", onClick: onCancel, disabled: isAdding, className: cn("rounded-md px-3 py-1 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] }));
}
// ---------------------------------------------------------------------------
// Shared primitives
// ---------------------------------------------------------------------------
function ActionButton({ onClick, disabled, label, variant, children, }) {
    const colorClass = {
        primary: "text-primary hover:text-primary-muted",
        muted: "text-muted-foreground hover:text-foreground",
        "muted-danger": "text-muted-foreground hover:text-destructive",
        danger: "text-destructive hover:text-destructive-muted",
    }[variant];
    return (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, "aria-label": label, className: cn("rounded p-1 transition-colors disabled:pointer-events-none disabled:opacity-40", colorClass), children: children }));
}
function RowError({ error }) {
    if (!error)
        return null;
    return (_jsx("p", { className: "text-destructive pb-1 text-[0.6rem]", role: "alert", children: getUserMessage(error) }));
}
// ---------------------------------------------------------------------------
// Icons (inline SVGs — SDK components avoid icon library dependencies)
// ---------------------------------------------------------------------------
function EyeIcon() {
    return (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M1.5 8s2.5-4.5 6.5-4.5S14.5 8 14.5 8s-2.5 4.5-6.5 4.5S1.5 8 1.5 8z" }), _jsx("circle", { cx: "8", cy: "8", r: "2" })] }));
}
function EyeOffIcon() {
    return (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M6.59 6.59a2 2 0 0 0 2.82 2.82" }), _jsx("path", { d: "M10.73 10.73A6.5 6.5 0 0 1 8 12.5c-4 0-6.5-4.5-6.5-4.5a11.5 11.5 0 0 1 3.77-3.73" }), _jsx("path", { d: "M5.71 3.56A6.3 6.3 0 0 1 8 3.5c4 0 6.5 4.5 6.5 4.5a11.5 11.5 0 0 1-1.28 1.73" }), _jsx("path", { d: "M2 2l12 12" })] }));
}
function PencilIcon() {
    return (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M11.5 2.5a1.4 1.4 0 0 1 2 2L5.5 12.5l-3 .5.5-3 8-8z" }) }));
}
function TrashIcon() {
    return (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M3 5h10" }), _jsx("path", { d: "M5.5 5V3.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1V5" }), _jsx("path", { d: "M4.5 5l.5 8a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1l.5-8" }), _jsx("path", { d: "M6.5 7.5v4M9.5 7.5v4" })] }));
}
function CheckIcon() {
    return (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M3.5 8.5l3 3 6-6" }) }));
}
function XIcon() {
    return (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) }));
}
function PlusIcon() {
    return (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M8 3v10M3 8h10" }) }));
}
function SpinnerIcon() {
    return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", className: "animate-spin", "aria-hidden": "true", children: _jsx("path", { d: "M8 2a6 6 0 1 0 6 6" }) }));
}
//# sourceMappingURL=EnvironmentVariableEditor.js.map