"use client";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useCallback, useState, } from "react";
import { cn } from "@stigmer/theme";
import { getUserMessage } from "@stigmer/sdk";
import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
import { timestampDate } from "@bufbuild/protobuf/wkt";
import { useUpdatePlatformClient } from "./useUpdatePlatformClient";
import { useRotatePlatformClientSecret } from "./useRotatePlatformClientSecret";
import { useDeletePlatformClient } from "./useDeletePlatformClient";
/**
 * View and edit panel for an existing platform client.
 *
 * In **view mode**, displays all configuration fields in a structured
 * label/value layout with "Edit", "Rotate Secret", and "Delete"
 * actions.
 *
 * In **edit mode**, mutable spec fields become editable: JIT
 * provisioning toggles, expiry, auto-grant role, and allowed
 * origins. Credential fields (`clientId`, `secretFingerprint`) are
 * read-only. "Save" submits the update; "Cancel" discards changes.
 *
 * Secret rotation triggers `onSecretRotated` with the full
 * {@link PlatformClientCreateResponse} so the parent can show the
 * one-time secret alert.
 *
 * All visual properties flow through `--stgm-*` design tokens.
 *
 * @example
 * ```tsx
 * <PlatformClientDetailPanel
 *   platformClient={pc}
 *   onUpdated={(updated) => refetch()}
 *   onSecretRotated={(resp) => setFlow({ phase: "revealing", resp })}
 *   onDeleted={() => setFlow({ phase: "idle" })}
 *   onBack={() => setFlow({ phase: "idle" })}
 * />
 * ```
 */
export function PlatformClientDetailPanel({ platformClient, onUpdated, onSecretRotated, onDeleted, onBack, className, }) {
    const spec = platformClient.spec;
    const meta = platformClient.metadata;
    const { update, isUpdating, error: updateError, clearError: clearUpdateError } = useUpdatePlatformClient();
    const { rotateSecret, isRotating, error: rotateError, clearError: clearRotateError } = useRotatePlatformClientSecret();
    const { deletePlatformClient, isDeleting, error: deleteError } = useDeletePlatformClient();
    const [mode, setMode] = useState("view");
    const [confirmingDelete, setConfirmingDelete] = useState(false);
    const [confirmingRotate, setConfirmingRotate] = useState(false);
    const isBusy = isUpdating || isRotating || isDeleting;
    // Edit form state
    const [neverExpires, setNeverExpires] = useState(spec?.neverExpires ?? true);
    const [expiresAt, setExpiresAt] = useState(() => {
        if (spec?.expiresAt) {
            return toDatetimeLocalValue(timestampDate(spec.expiresAt));
        }
        return "";
    });
    const [autoProvision, setAutoProvision] = useState(spec?.autoProvisionAccounts ?? false);
    const [autoGrant, setAutoGrant] = useState(spec?.autoGrantOnOrg ?? false);
    const [autoGrantRole, setAutoGrantRole] = useState(spec?.autoGrantRole ?? IamRole.iam_role_unspecified);
    const [origins, setOrigins] = useState([...(spec?.allowedOrigins ?? [])]);
    const [originInput, setOriginInput] = useState("");
    const handleAutoProvisionChange = useCallback((v) => {
        setAutoProvision(v);
        if (!v) {
            setAutoGrant(false);
            setAutoGrantRole(IamRole.iam_role_unspecified);
        }
    }, []);
    const handleAutoGrantChange = useCallback((v) => {
        setAutoGrant(v);
        if (v)
            setAutoProvision(true);
        if (!v)
            setAutoGrantRole(IamRole.iam_role_unspecified);
    }, []);
    const addOrigin = useCallback(() => {
        const trimmed = originInput.trim();
        if (trimmed && !origins.includes(trimmed)) {
            setOrigins((prev) => [...prev, trimmed]);
        }
        setOriginInput("");
    }, [originInput, origins]);
    const handleOriginKeyDown = useCallback((e) => {
        if (e.key === "Enter") {
            e.preventDefault();
            addOrigin();
        }
    }, [addOrigin]);
    const removeOrigin = useCallback((origin) => {
        setOrigins((prev) => prev.filter((o) => o !== origin));
    }, []);
    const enterEdit = useCallback(() => {
        setNeverExpires(spec?.neverExpires ?? true);
        setExpiresAt(spec?.expiresAt
            ? toDatetimeLocalValue(timestampDate(spec.expiresAt))
            : "");
        setAutoProvision(spec?.autoProvisionAccounts ?? false);
        setAutoGrant(spec?.autoGrantOnOrg ?? false);
        setAutoGrantRole(spec?.autoGrantRole ?? IamRole.iam_role_unspecified);
        setOrigins([...(spec?.allowedOrigins ?? [])]);
        setOriginInput("");
        clearUpdateError();
        setMode("edit");
    }, [spec, clearUpdateError]);
    const cancelEdit = useCallback(() => {
        clearUpdateError();
        setMode("view");
    }, [clearUpdateError]);
    const handleSave = useCallback(async (e) => {
        e.preventDefault();
        clearUpdateError();
        try {
            const updated = await update({
                name: meta?.name ?? "",
                slug: meta?.slug,
                org: meta?.org ?? "",
                neverExpires,
                ...(!neverExpires &&
                    expiresAt && {
                    expiresAt: new Date(expiresAt).toISOString(),
                }),
                autoProvisionAccounts: autoProvision,
                autoGrantOnOrg: autoGrant,
                ...(autoGrant &&
                    autoGrantRole !== IamRole.iam_role_unspecified && {
                    autoGrantRole,
                }),
                allowedOrigins: origins,
            });
            setMode("view");
            onUpdated?.(updated);
        }
        catch {
            // error state is managed by useUpdatePlatformClient
        }
    }, [
        meta,
        neverExpires,
        expiresAt,
        autoProvision,
        autoGrant,
        autoGrantRole,
        origins,
        update,
        clearUpdateError,
        onUpdated,
    ]);
    const handleRotateSecret = useCallback(async () => {
        clearRotateError();
        try {
            const response = await rotateSecret(meta?.id ?? "");
            setConfirmingRotate(false);
            onSecretRotated?.(response);
        }
        catch {
            // error state is managed by the hook
        }
    }, [meta?.id, rotateSecret, clearRotateError, onSecretRotated]);
    const handleDelete = useCallback(async () => {
        try {
            await deletePlatformClient({ resourceId: meta?.id ?? "" });
            onDeleted?.();
        }
        catch {
            // error state is surfaced via the hook
        }
    }, [meta?.id, deletePlatformClient, onDeleted]);
    const createdAt = platformClient.status?.audit?.specAudit?.createdAt;
    const updatedAt = platformClient.status?.audit?.specAudit?.updatedAt;
    return (_jsxs("div", { className: cn("space-y-4", className), children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [onBack && (_jsxs("button", { type: "button", onClick: onBack, className: "text-muted-foreground hover:text-foreground mb-1 flex items-center gap-1 text-xs transition-colors", children: [_jsx(ArrowLeftIcon, {}), "Back to list"] })), _jsx("h3", { className: "text-foreground truncate text-sm font-semibold", children: meta?.name ?? "Platform Client" }), _jsxs("div", { className: "flex items-center gap-2", children: [meta?.slug && (_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: meta.slug })), spec?.autoProvisionAccounts && (_jsx("span", { className: "inline-flex items-center rounded-full border border-primary/30 bg-primary-subtle px-2 py-0.5 text-[0.65rem] font-medium text-primary", children: "JIT" }))] })] }), mode === "view" && (_jsx("button", { type: "button", onClick: enterEdit, className: cn("shrink-0 rounded-md px-2.5 py-1.5 text-xs font-medium", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "transition-colors"), children: "Edit" }))] }), mode === "view" ? (_jsx(ViewMode, { spec: spec, createdAt: createdAt, updatedAt: updatedAt })) : (_jsxs("form", { onSubmit: handleSave, className: "space-y-3", children: [_jsxs("div", { className: "rounded-md border border-border-muted bg-muted-faint px-3 py-2 space-y-1", children: [_jsx("p", { className: "text-[0.65rem] font-medium text-muted-foreground", children: "Client ID" }), _jsx("p", { className: "font-mono text-xs text-foreground", children: spec?.clientId ?? "—" })] }), _jsxs("fieldset", { className: "space-y-2", disabled: isUpdating, children: [_jsx("legend", { className: "text-xs font-medium text-foreground", children: "Expiry" }), _jsx(ToggleSwitch, { checked: neverExpires, onChange: setNeverExpires, label: "Never expires", disabled: isUpdating }), !neverExpires && (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: "stgm-pc-edit-expires-at", className: "text-xs font-medium text-foreground", children: "Expires at" }), _jsx("input", { id: "stgm-pc-edit-expires-at", type: "datetime-local", value: expiresAt, onChange: (e) => setExpiresAt(e.target.value), disabled: isUpdating, className: cn("w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50") })] }))] }), _jsxs("fieldset", { className: "space-y-2.5", disabled: isUpdating, children: [_jsx("hr", { className: "border-border-muted" }), _jsx("legend", { className: "text-xs font-medium text-foreground", children: "JIT provisioning" }), _jsx(ToggleSwitch, { checked: autoProvision, onChange: handleAutoProvisionChange, label: "Auto-provision accounts", hint: "Create a Stigmer identity account automatically on first token mint", disabled: isUpdating }), _jsx(ToggleSwitch, { checked: autoGrant, onChange: handleAutoGrantChange, label: "Auto-grant on organization", hint: "Grant a role on the owning organization when an account is provisioned", disabled: isUpdating || !autoProvision }), autoGrant && (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: "stgm-pc-edit-grant-role", className: "text-xs font-medium text-foreground", children: "Auto-grant role" }), _jsx("select", { id: "stgm-pc-edit-grant-role", value: String(autoGrantRole), onChange: (e) => setAutoGrantRole(Number(e.target.value)), disabled: isUpdating, className: cn("w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50"), children: JIT_ROLE_OPTIONS.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value))) })] }))] }), _jsxs("fieldset", { className: "space-y-2", disabled: isUpdating, children: [_jsx("hr", { className: "border-border-muted" }), _jsx("legend", { className: "text-xs font-medium text-foreground", children: "Allowed origins" }), _jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: "Browser origins permitted to use tokens minted by this client. Leave empty to allow all origins." }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: originInput, onChange: (e) => setOriginInput(e.target.value), onKeyDown: handleOriginKeyDown, onBlur: () => {
                                            if (originInput.trim())
                                                addOrigin();
                                        }, placeholder: "https://example.com", disabled: isUpdating, className: cn("min-w-0 flex-1 rounded-md border border-input bg-background px-2.5 py-1.5 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") }), _jsx("button", { type: "button", onClick: addOrigin, disabled: isUpdating || !originInput.trim(), className: cn("shrink-0 rounded-md px-2.5 py-1.5 text-xs font-medium", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "disabled:pointer-events-none disabled:opacity-50", "transition-colors"), children: "Add" })] }), origins.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1.5", children: origins.map((origin) => (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border border-border-muted bg-muted-subtle px-2 py-0.5 text-[0.65rem] font-mono text-foreground", children: [origin, _jsx("button", { type: "button", onClick: () => removeOrigin(origin), disabled: isUpdating, "aria-label": `Remove ${origin}`, className: "text-muted-foreground hover:text-destructive transition-colors", children: _jsx(XIcon, {}) })] }, origin))) }))] }), updateError && (_jsx("p", { className: "text-destructive text-[0.65rem]", role: "alert", children: getUserMessage(updateError) })), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsxs("button", { type: "submit", disabled: isUpdating, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium", "bg-primary text-primary-foreground hover:bg-primary-hover", "disabled:pointer-events-none disabled:opacity-40"), children: [isUpdating && _jsx(SpinnerIcon, {}), "Save changes"] }), _jsx("button", { type: "button", onClick: cancelEdit, disabled: isUpdating, className: cn("rounded-md px-2.5 py-1.5 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] })), mode === "view" && (_jsxs("div", { className: "space-y-2 pt-2", children: [_jsx("hr", { className: "border-border-muted" }), confirmingRotate ? (_jsxs("div", { className: "flex items-center justify-between rounded-md border border-warning/30 bg-warning/5 px-3 py-2", children: [_jsxs("p", { className: "text-xs text-foreground", children: ["Rotate secret? The current secret will be", _jsx("span", { className: "font-medium", children: " permanently invalidated" }), "."] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [_jsxs("button", { type: "button", onClick: handleRotateSecret, disabled: isBusy, className: cn("inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium", "bg-primary text-primary-foreground hover:bg-primary-hover", "disabled:pointer-events-none disabled:opacity-50"), children: [isRotating && _jsx(SpinnerIcon, {}), "Rotate"] }), _jsx("button", { type: "button", onClick: () => {
                                            setConfirmingRotate(false);
                                            clearRotateError();
                                        }, disabled: isBusy, className: cn("rounded-md px-2.5 py-1 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] })) : (_jsx("button", { type: "button", onClick: () => setConfirmingRotate(true), disabled: isBusy, className: cn("rounded-md px-2.5 py-1.5 text-xs font-medium", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "disabled:pointer-events-none disabled:opacity-50", "transition-colors"), children: "Rotate secret" })), rotateError && (_jsx("p", { className: "text-destructive text-[0.65rem]", role: "alert", children: getUserMessage(rotateError) })), confirmingDelete ? (_jsxs("div", { className: "flex items-center justify-between rounded-md border border-destructive/30 bg-destructive-subtle px-3 py-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("p", { className: "text-xs text-foreground", children: ["Delete", " ", _jsx("span", { className: "font-medium", children: meta?.name }), "? This action is permanent."] }), deleteError && (_jsx("p", { className: "mt-0.5 text-[0.65rem] text-destructive", children: getUserMessage(deleteError) }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [_jsxs("button", { type: "button", onClick: handleDelete, disabled: isBusy, className: cn("inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium", "bg-destructive text-destructive-foreground hover:bg-destructive-hover", "disabled:pointer-events-none disabled:opacity-50"), children: [isDeleting && _jsx(SpinnerIcon, {}), "Delete"] }), _jsx("button", { type: "button", onClick: () => setConfirmingDelete(false), disabled: isBusy, className: cn("rounded-md px-2.5 py-1 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent-hover", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] })) : (_jsx("button", { type: "button", onClick: () => setConfirmingDelete(true), disabled: isBusy, className: cn("rounded-md px-2.5 py-1.5 text-xs font-medium", "text-destructive hover:text-destructive-foreground hover:bg-destructive-hover", "disabled:pointer-events-none disabled:opacity-50", "transition-colors"), children: "Delete platform client" }))] }))] }));
}
// ---------------------------------------------------------------------------
// View mode
// ---------------------------------------------------------------------------
function ViewMode({ spec, createdAt, updatedAt, }) {
    return (_jsxs("dl", { className: "space-y-2.5", children: [_jsx(Field, { label: "Client ID", value: spec?.clientId, mono: true }), _jsx(Field, { label: "Secret fingerprint", value: spec?.secretFingerprint
                    ? `••••${spec.secretFingerprint.slice(-4)}`
                    : undefined, mono: true }), spec?.neverExpires ? (_jsx(Field, { label: "Expiry", value: "Never expires" })) : spec?.expiresAt ? (_jsx(Field, { label: "Expires", value: formatDate(timestampDate(spec.expiresAt)) })) : null, _jsx("hr", { className: "border-border-muted" }), _jsx(Field, { label: "Auto-provision accounts", value: spec?.autoProvisionAccounts ? "Enabled" : "Disabled" }), _jsx(Field, { label: "Auto-grant on organization", value: spec?.autoGrantOnOrg ? "Enabled" : "Disabled" }), spec?.autoGrantOnOrg && (_jsx(Field, { label: "Auto-grant role", value: formatIamRole(spec.autoGrantRole) })), (spec?.allowedOrigins.length ?? 0) > 0 && (_jsxs(_Fragment, { children: [_jsx("hr", { className: "border-border-muted" }), _jsxs("div", { children: [_jsx("dt", { className: "text-muted-foreground text-[0.65rem] font-medium", children: "Allowed origins" }), _jsx("dd", { className: "mt-0.5 flex flex-wrap gap-1.5", children: spec.allowedOrigins.map((origin) => (_jsx("span", { className: "inline-block rounded-full border border-border-muted bg-muted-subtle px-2 py-0.5 text-[0.65rem] font-mono text-foreground", children: origin }, origin))) })] })] })), _jsxs("div", { className: "flex gap-6", children: [createdAt && (_jsx(Field, { label: "Created", value: formatDate(timestampDate(createdAt)) })), updatedAt && (_jsx(Field, { label: "Updated", value: formatDate(timestampDate(updatedAt)) }))] })] }));
}
// ---------------------------------------------------------------------------
// Shared primitives
// ---------------------------------------------------------------------------
function Field({ label, value, mono, }) {
    if (!value)
        return null;
    return (_jsxs("div", { children: [_jsx("dt", { className: "text-muted-foreground text-[0.65rem] font-medium", children: label }), _jsx("dd", { className: cn("text-foreground mt-0.5 break-all text-xs", mono && "font-mono"), children: value })] }));
}
function ToggleSwitch({ checked, onChange, label, hint, disabled, }) {
    return (_jsxs("div", { className: "space-y-0.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", role: "switch", "aria-checked": checked, onClick: () => onChange(!checked), disabled: disabled, className: cn("relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors", checked ? "bg-primary" : "bg-muted", "disabled:pointer-events-none disabled:opacity-50"), children: _jsx("span", { className: cn("pointer-events-none inline-block h-4 w-4 rounded-full bg-background shadow-sm ring-0 transition-transform", checked ? "translate-x-4" : "translate-x-0") }) }), _jsx("span", { className: "text-xs font-medium text-foreground", children: label })] }), hint && (_jsx("p", { className: "pl-11 text-[0.65rem] text-muted-foreground", children: hint }))] }));
}
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const JIT_ROLE_OPTIONS = [
    { value: String(IamRole.iam_role_unspecified), label: "Default (viewer)" },
    { value: String(IamRole.viewer), label: "Viewer" },
    { value: String(IamRole.member), label: "Member" },
    { value: String(IamRole.admin), label: "Admin" },
];
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function formatIamRole(role) {
    switch (role) {
        case IamRole.viewer:
            return "Viewer";
        case IamRole.member:
            return "Member";
        case IamRole.admin:
            return "Admin";
        case IamRole.owner:
            return "Owner";
        default:
            return "Viewer (default)";
    }
}
function formatDate(date) {
    return date.toLocaleDateString(undefined, {
        month: "short",
        day: "numeric",
        year: "numeric",
    });
}
function toDatetimeLocalValue(date) {
    const pad = (n) => String(n).padStart(2, "0");
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
}
// ---------------------------------------------------------------------------
// Icons
// ---------------------------------------------------------------------------
function XIcon() {
    return (_jsx("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: _jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) }));
}
function ArrowLeftIcon() {
    return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M10 3L5 8l5 5" }) }));
}
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=PlatformClientDetailPanel.js.map