"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useState } from "react";
import { cn } from "@stigmer/theme";
import { getUserMessage } from "@stigmer/sdk";
import { VendorApprovalStatus } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/spec_pb";
import { timestampDate } from "@bufbuild/protobuf/wkt";
import { useUpdateOAuthApp } from "./useUpdateOAuthApp";
import { useDeleteOAuthApp } from "./useDeleteOAuthApp";
/**
 * View and edit panel for an existing OAuth app.
 *
 * In **view mode**, displays all OAuth configuration fields in a
 * structured label/value layout with "Edit" and "Delete" buttons.
 *
 * In **edit mode**, fields become editable inputs. The client secret
 * field shows a placeholder — leave it empty to keep the existing
 * secret, or enter a new value to replace it. "Save" submits the
 * update via {@link useUpdateOAuthApp}; "Cancel" discards changes
 * and returns to view mode.
 *
 * Delete uses an inline confirmation pattern (no modal) to avoid
 * portal/z-index issues for SDK embedders.
 *
 * All visual properties flow through `--stgm-*` design tokens.
 *
 * @example
 * ```tsx
 * <OAuthAppDetailPanel
 *   oauthApp={app}
 *   onUpdated={(updated) => refetch()}
 *   onDeleted={() => { refetch(); setFlow({ phase: "idle" }); }}
 *   onBack={() => setFlow({ phase: "idle" })}
 * />
 * ```
 */
export function OAuthAppDetailPanel({ oauthApp, onUpdated, onDeleted, onBack, className, }) {
    const spec = oauthApp.spec;
    const meta = oauthApp.metadata;
    const { update, isUpdating, error: updateError, clearError: clearUpdateError } = useUpdateOAuthApp();
    const { deleteApp, isDeleting, error: deleteError, clearError: clearDeleteError } = useDeleteOAuthApp();
    const [mode, setMode] = useState("view");
    const [confirmingDelete, setConfirmingDelete] = useState(false);
    // Edit form state — initialized from current resource
    const [provider, setProvider] = useState(spec?.provider ?? "");
    const [clientId, setClientId] = useState(spec?.clientId ?? "");
    const [clientSecret, setClientSecret] = useState("");
    const [authorizationUrl, setAuthorizationUrl] = useState(spec?.authorizationUrl ?? "");
    const [tokenUrl, setTokenUrl] = useState(spec?.tokenUrl ?? "");
    const [scopes, setScopes] = useState(spec?.scopes.join(", ") ?? "");
    const [userinfoUrl, setUserinfoUrl] = useState(spec?.userinfoUrl ?? "");
    const [scopeParameterName, setScopeParameterName] = useState(spec?.scopeParameterName ?? "");
    const [vendorApprovalStatus, setVendorApprovalStatus] = useState(approvalStatusToKey(spec?.vendorApprovalStatus));
    const [vendorApprovalDocsUrl, setVendorApprovalDocsUrl] = useState(spec?.vendorApprovalDocsUrl ?? "");
    const enterEdit = useCallback(() => {
        setProvider(spec?.provider ?? "");
        setClientId(spec?.clientId ?? "");
        setClientSecret("");
        setAuthorizationUrl(spec?.authorizationUrl ?? "");
        setTokenUrl(spec?.tokenUrl ?? "");
        setScopes(spec?.scopes.join(", ") ?? "");
        setUserinfoUrl(spec?.userinfoUrl ?? "");
        setScopeParameterName(spec?.scopeParameterName ?? "");
        setVendorApprovalStatus(approvalStatusToKey(spec?.vendorApprovalStatus));
        setVendorApprovalDocsUrl(spec?.vendorApprovalDocsUrl ?? "");
        clearUpdateError();
        setMode("edit");
    }, [spec, clearUpdateError]);
    const cancelEdit = useCallback(() => {
        clearUpdateError();
        setMode("view");
    }, [clearUpdateError]);
    const handleSave = useCallback(async (e) => {
        e.preventDefault();
        clearUpdateError();
        const parsedScopes = scopes
            .split(",")
            .map((s) => s.trim())
            .filter(Boolean);
        try {
            const updated = await update({
                name: meta?.name ?? "",
                slug: meta?.slug,
                org: meta?.org ?? "",
                provider: provider.trim(),
                clientId: clientId.trim(),
                ...(clientSecret.trim() && { clientSecret: clientSecret.trim() }),
                authorizationUrl: authorizationUrl.trim(),
                tokenUrl: tokenUrl.trim(),
                ...(parsedScopes.length > 0 && { scopes: parsedScopes }),
                ...(userinfoUrl.trim() && { userinfoUrl: userinfoUrl.trim() }),
                ...(scopeParameterName.trim() && {
                    scopeParameterName: scopeParameterName.trim(),
                }),
                ...(vendorApprovalStatus !== "unspecified" && {
                    vendorApprovalStatus: APPROVAL_STATUS_MAP[vendorApprovalStatus],
                }),
                ...(vendorApprovalDocsUrl.trim() && {
                    vendorApprovalDocsUrl: vendorApprovalDocsUrl.trim(),
                }),
            });
            setMode("view");
            onUpdated?.(updated);
        }
        catch {
            // error state is managed by useUpdateOAuthApp
        }
    }, [
        meta, provider, clientId, clientSecret, authorizationUrl, tokenUrl,
        scopes, userinfoUrl, scopeParameterName, vendorApprovalStatus,
        vendorApprovalDocsUrl, update, clearUpdateError, onUpdated,
    ]);
    const handleDelete = useCallback(async () => {
        const id = meta?.id;
        if (!id)
            return;
        clearDeleteError();
        try {
            await deleteApp(id);
            onDeleted?.();
        }
        catch {
            // error state is managed by useDeleteOAuthApp
        }
    }, [meta, deleteApp, clearDeleteError, onDeleted]);
    const canSave = provider.trim() !== "" &&
        clientId.trim() !== "" &&
        authorizationUrl.trim() !== "" &&
        tokenUrl.trim() !== "" &&
        !isUpdating;
    const createdAt = oauthApp.status?.audit?.specAudit?.createdAt;
    const updatedAt = oauthApp.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: spec?.provider || meta?.name || "OAuth App" }), meta?.slug && (_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: meta.slug }))] }), mode === "view" && (_jsxs("div", { className: "flex items-center gap-1", children: [_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" }), _jsx("button", { type: "button", onClick: () => {
                                    clearDeleteError();
                                    setConfirmingDelete(true);
                                }, className: cn("shrink-0 rounded-md px-2.5 py-1.5 text-xs font-medium", "text-destructive-muted hover:text-destructive hover:bg-destructive-subtle", "transition-colors"), children: "Delete" })] }))] }), confirmingDelete && (_jsxs("div", { className: "rounded-md border border-destructive/30 bg-destructive-subtle p-3", role: "alert", children: [_jsx("p", { className: "text-foreground mb-2 text-xs font-medium", children: "Delete this OAuth app?" }), _jsx("p", { className: "text-muted-foreground mb-3 text-[0.65rem]", children: "This action is permanent. Any MCP server overrides referencing this app will lose their binding." }), deleteError && (_jsx("p", { className: "text-destructive mb-2 text-[0.65rem]", role: "alert", children: getUserMessage(deleteError) })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "button", onClick: handleDelete, disabled: isDeleting, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium", "bg-destructive text-destructive-foreground hover:bg-destructive-hover", "disabled:pointer-events-none disabled:opacity-40"), children: [isDeleting && _jsx(SpinnerIcon, {}), "Delete permanently"] }), _jsx("button", { type: "button", onClick: () => {
                                    setConfirmingDelete(false);
                                    clearDeleteError();
                                }, disabled: isDeleting, 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" ? (_jsx(ViewMode, { spec: spec, createdAt: createdAt, updatedAt: updatedAt })) : (_jsxs("form", { onSubmit: handleSave, className: "space-y-3", children: [_jsx(FieldInput, { id: "stgm-oauth-edit-provider", label: "Provider", value: provider, onChange: setProvider, placeholder: "e.g. Slack", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-client-id", label: "Client ID", value: clientId, onChange: setClientId, placeholder: "OAuth client identifier", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-client-secret", label: "Client secret", value: clientSecret, onChange: setClientSecret, placeholder: "Leave empty to keep existing secret", type: "password", hint: "Only enter a value to replace the existing secret", disabled: isUpdating }), _jsx(FieldInput, { id: "stgm-oauth-edit-auth-url", label: "Authorization URL", value: authorizationUrl, onChange: setAuthorizationUrl, placeholder: "https://vendor.com/oauth/authorize", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-token-url", label: "Token URL", value: tokenUrl, onChange: setTokenUrl, placeholder: "https://vendor.com/oauth/token", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-scopes", label: "Scopes", value: scopes, onChange: setScopes, placeholder: "read, write, admin", hint: "Comma-separated OAuth scopes", disabled: isUpdating }), _jsx(FieldInput, { id: "stgm-oauth-edit-userinfo-url", label: "Userinfo URL", value: userinfoUrl, onChange: setUserinfoUrl, placeholder: "https://vendor.com/userinfo", hint: "OIDC endpoint for fetching user profile data (optional)", disabled: isUpdating }), _jsx(FieldInput, { id: "stgm-oauth-edit-scope-param", label: "Scope parameter name", value: scopeParameterName, onChange: setScopeParameterName, placeholder: "scope", hint: 'Defaults to "scope". Some vendors use a non-standard name.', disabled: isUpdating }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: "stgm-oauth-edit-approval-status", className: "text-xs font-medium text-foreground", children: "Vendor approval status" }), _jsxs("select", { id: "stgm-oauth-edit-approval-status", value: vendorApprovalStatus, onChange: (e) => setVendorApprovalStatus(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: [_jsx("option", { value: "unspecified", children: "Unspecified (treated as approved)" }), _jsx("option", { value: "pending", children: "Pending" }), _jsx("option", { value: "approved", children: "Approved" }), _jsx("option", { value: "rejected", children: "Rejected" })] })] }), _jsx(FieldInput, { id: "stgm-oauth-edit-approval-docs", label: "Vendor approval docs URL", value: vendorApprovalDocsUrl, onChange: setVendorApprovalDocsUrl, placeholder: "https://docs.example.com/byoa", hint: "Help link shown when vendor approval is pending", disabled: isUpdating }), 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: !canSave, 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" })] })] }))] }));
}
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const APPROVAL_STATUS_MAP = {
    pending: VendorApprovalStatus.PENDING,
    approved: VendorApprovalStatus.APPROVED,
    rejected: VendorApprovalStatus.REJECTED,
};
const APPROVAL_STATUS_LABELS = {
    [VendorApprovalStatus.UNSPECIFIED]: "Unspecified",
    [VendorApprovalStatus.PENDING]: "Pending",
    [VendorApprovalStatus.APPROVED]: "Approved",
    [VendorApprovalStatus.REJECTED]: "Rejected",
};
function approvalStatusToKey(status) {
    switch (status) {
        case VendorApprovalStatus.PENDING:
            return "pending";
        case VendorApprovalStatus.APPROVED:
            return "approved";
        case VendorApprovalStatus.REJECTED:
            return "rejected";
        default:
            return "unspecified";
    }
}
// ---------------------------------------------------------------------------
// View mode
// ---------------------------------------------------------------------------
function ViewMode({ spec, createdAt, updatedAt, }) {
    return (_jsxs("dl", { className: "space-y-2.5", children: [_jsx(Field, { label: "Provider", value: spec?.provider }), _jsx(Field, { label: "Client ID", value: spec?.clientId, mono: true }), _jsx(Field, { label: "Client secret", value: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), _jsx(Field, { label: "Authorization URL", value: spec?.authorizationUrl, mono: true }), _jsx(Field, { label: "Token URL", value: spec?.tokenUrl, mono: true }), spec?.scopes && spec.scopes.length > 0 && (_jsx(Field, { label: "Scopes", value: spec.scopes.join(", "), mono: true })), spec?.userinfoUrl && (_jsx(Field, { label: "Userinfo URL", value: spec.userinfoUrl, mono: true })), spec?.scopeParameterName && (_jsx(Field, { label: "Scope parameter name", value: spec.scopeParameterName, mono: true })), spec?.vendorApprovalStatus !== undefined &&
                spec.vendorApprovalStatus !== VendorApprovalStatus.UNSPECIFIED && (_jsx(Field, { label: "Vendor approval", value: APPROVAL_STATUS_LABELS[spec.vendorApprovalStatus] ??
                    "Unknown" })), spec?.vendorApprovalDocsUrl && (_jsx(Field, { label: "Approval docs", value: spec.vendorApprovalDocsUrl, mono: true })), _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 FieldInput({ id, label, value, onChange, placeholder, hint, type = "text", disabled, required, }) {
    return (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: id, className: "text-xs font-medium text-foreground", children: label }), _jsx("input", { id: id, type: type, value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, disabled: disabled, required: required, className: cn("w-full 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") }), hint && (_jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: hint }))] }));
}
function formatDate(date) {
    return date.toLocaleDateString(undefined, {
        month: "short",
        day: "numeric",
        year: "numeric",
    });
}
// ---------------------------------------------------------------------------
// Icons
// ---------------------------------------------------------------------------
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=OAuthAppDetailPanel.js.map