"use client";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } 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 { ProviderPicker } from "./ProviderPicker";
import { useCreateIdentityProvider } from "./useCreateIdentityProvider";
import { useOidcDiscovery } from "./useOidcDiscovery";
/**
 * Multi-step wizard for creating a new identity provider.
 *
 * Guides the user through three steps:
 *
 * 1. **Pick** — select a well-known provider preset or "Custom OIDC"
 * 2. **Configure** — fill in provider-specific variables (e.g., Auth0
 *    tenant name) plus the IdP display name and expected audience
 * 3. **Review** — verify auto-populated OIDC configuration, optionally
 *    enable SSO, and submit
 *
 * For known presets, URLs are constructed from deterministic templates
 * (no network call). For "Custom OIDC", the wizard attempts OIDC
 * Discovery and falls back to manual entry if the fetch fails.
 *
 * All visual properties flow through `--stgm-*` design tokens.
 *
 * @example
 * ```tsx
 * <IdentityProviderWizard
 *   org="acme"
 *   onCreated={(idp) => { refetch(); setShowWizard(false); }}
 *   onCancel={() => setShowWizard(false)}
 * />
 * ```
 */
export function IdentityProviderWizard({ org, onCreated, onCancel, className, }) {
    const { create, isCreating, error: createError, clearError } = useCreateIdentityProvider();
    const { discover, isDiscovering, error: discoveryError } = useOidcDiscovery();
    // Step state
    const [step, setStep] = useState("pick");
    const [preset, setPreset] = useState(null);
    // Configure step
    const [vars, setVars] = useState({});
    const [name, setName] = useState("");
    const [audience, setAudience] = useState("");
    // Review step
    const [jwksUri, setJwksUri] = useState("");
    const [issuers, setIssuers] = useState("");
    const [userinfoEndpoint, setUserinfoEndpoint] = useState("");
    const [isSso, setIsSso] = useState(false);
    const [oidcClientId, setOidcClientId] = useState("");
    const [discoveryFailed, setDiscoveryFailed] = useState(false);
    // JIT provisioning
    const [autoProvision, setAutoProvision] = useState(false);
    const [autoGrant, setAutoGrant] = useState(false);
    const [autoGrantRole, setAutoGrantRole] = useState(IamRole.iam_role_unspecified);
    const [tenantOrgClaim, setTenantOrgClaim] = useState("");
    // Success step
    const [createdIdp, setCreatedIdp] = useState(null);
    // -- Step transitions ------------------------------------------------
    const handlePickProvider = useCallback((selected) => {
        setPreset(selected);
        setVars(Object.fromEntries(selected.variables.map((v) => [v.key, v.options?.[0]?.value ?? ""])));
        setName("");
        setAudience("");
        setStep("configure");
    }, []);
    const handleBackToPick = useCallback(() => {
        setStep("pick");
        setPreset(null);
    }, []);
    const populateReview = useCallback((config) => {
        setJwksUri(config?.jwksUri ?? "");
        setIssuers(config?.allowedIssuers.join(", ") ?? "");
        setUserinfoEndpoint(config?.userinfoEndpoint ?? "");
        setIsSso(false);
        setOidcClientId("");
        setDiscoveryFailed(!config);
    }, []);
    const handleContinueToReview = useCallback(async () => {
        if (!preset)
            return;
        if (preset.id === "custom") {
            const result = await discover(vars.issuerUrl ?? "");
            populateReview(result
                ? { ...result, allowedIssuers: [result.issuer] }
                : null);
        }
        else {
            populateReview(preset.buildConfig(vars));
        }
        setStep("review");
    }, [preset, vars, discover, populateReview]);
    const handleBackToConfigure = useCallback(() => {
        setStep("configure");
        clearError();
    }, [clearError]);
    // -- Submit ----------------------------------------------------------
    const handleAutoProvisionChange = useCallback((v) => {
        setAutoProvision(v);
        if (!v) {
            setAutoGrant(false);
            setAutoGrantRole(IamRole.iam_role_unspecified);
            setTenantOrgClaim("");
        }
    }, []);
    const handleAutoGrantChange = useCallback((v) => {
        setAutoGrant(v);
        if (v)
            setAutoProvision(true);
        if (!v) {
            setAutoGrantRole(IamRole.iam_role_unspecified);
            setTenantOrgClaim("");
        }
    }, []);
    const handleSubmit = useCallback(async (e) => {
        e.preventDefault();
        clearError();
        try {
            const idp = await create({
                name: name.trim(),
                org,
                displayName: name.trim(),
                jwksUri: jwksUri.trim(),
                allowedIssuers: issuers
                    .split(",")
                    .map((s) => s.trim())
                    .filter(Boolean),
                expectedAudience: audience.trim(),
                userinfoEndpoint: userinfoEndpoint.trim() || undefined,
                ...(isSso && {
                    isSsoProvider: true,
                    oidcClientId: oidcClientId.trim(),
                }),
                ...(!isSso && {
                    autoProvisionAccounts: autoProvision,
                    autoGrantOnOrg: autoGrant,
                    ...(autoGrant && autoGrantRole !== IamRole.iam_role_unspecified && {
                        autoGrantRole,
                    }),
                    ...(autoGrant && tenantOrgClaim.trim() && {
                        tenantOrgClaim: tenantOrgClaim.trim(),
                    }),
                }),
            });
            setCreatedIdp(idp);
            setStep("success");
        }
        catch {
            // error state is managed by useCreateIdentityProvider
        }
    }, [
        name, org, jwksUri, issuers, audience, userinfoEndpoint,
        isSso, oidcClientId, autoProvision, autoGrant, autoGrantRole,
        tenantOrgClaim, create, clearError,
    ]);
    // -- Render ----------------------------------------------------------
    return (_jsxs("div", { className: cn("space-y-4", className), children: [_jsx(StepIndicator, { current: step }), step === "pick" && (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-muted-foreground text-xs", children: "Choose your identity provider to get started. Known providers will have their OIDC configuration auto-populated." }), _jsx(ProviderPicker, { onSelect: handlePickProvider }), onCancel && (_jsx("div", { className: "pt-1", children: _jsx(CancelButton, { onClick: onCancel }) }))] })), step === "configure" && preset && (_jsx(ConfigureStep, { preset: preset, vars: vars, onVarChange: (key, value) => setVars((prev) => ({ ...prev, [key]: value })), name: name, onNameChange: setName, audience: audience, onAudienceChange: setAudience, isLoading: isDiscovering, discoveryError: discoveryError, onBack: handleBackToPick, onContinue: handleContinueToReview, onCancel: onCancel })), step === "review" && (_jsx(ReviewStep, { discoveryFailed: discoveryFailed, jwksUri: jwksUri, onJwksUriChange: setJwksUri, issuers: issuers, onIssuersChange: setIssuers, userinfoEndpoint: userinfoEndpoint, onUserinfoEndpointChange: setUserinfoEndpoint, isSso: isSso, onIsSsoChange: setIsSso, oidcClientId: oidcClientId, onOidcClientIdChange: setOidcClientId, autoProvision: autoProvision, onAutoProvisionChange: handleAutoProvisionChange, autoGrant: autoGrant, onAutoGrantChange: handleAutoGrantChange, autoGrantRole: autoGrantRole, onAutoGrantRoleChange: setAutoGrantRole, tenantOrgClaim: tenantOrgClaim, onTenantOrgClaimChange: setTenantOrgClaim, isCreating: isCreating, createError: createError, onBack: handleBackToConfigure, onSubmit: handleSubmit, onCancel: onCancel })), step === "success" && createdIdp && (_jsx(SuccessStep, { identityProvider: createdIdp, org: org, isSso: isSso, autoProvision: autoProvision, autoGrant: autoGrant, autoGrantRole: autoGrantRole, onDone: () => onCreated?.(createdIdp) }))] }));
}
// ---------------------------------------------------------------------------
// Step indicator
// ---------------------------------------------------------------------------
const STEPS = [
    { key: "pick", label: "Provider" },
    { key: "configure", label: "Configure" },
    { key: "review", label: "Review" },
    { key: "success", label: "Done" },
];
function StepIndicator({ current }) {
    const currentIdx = STEPS.findIndex((s) => s.key === current);
    return (_jsx("nav", { "aria-label": "Wizard progress", className: "flex items-center gap-1.5", children: STEPS.map((s, i) => {
            const state = i < currentIdx ? "done" : i === currentIdx ? "active" : "upcoming";
            return (_jsxs("span", { className: "flex items-center gap-1.5", children: [i > 0 && (_jsx("span", { className: cn("h-px w-4", state === "upcoming" ? "bg-border" : "bg-primary-subtle") })), _jsx("span", { className: cn("text-[0.65rem] font-medium", state === "active"
                            ? "text-primary"
                            : state === "done"
                                ? "text-muted-foreground"
                                : "text-muted-foreground-faint"), children: s.label })] }, s.key));
        }) }));
}
// ---------------------------------------------------------------------------
// Configure step (step 2)
// ---------------------------------------------------------------------------
function ConfigureStep({ preset, vars, onVarChange, name, onNameChange, audience, onAudienceChange, isLoading, discoveryError, onBack, onContinue, onCancel, }) {
    const allVarsFilled = preset.variables.every((v) => (vars[v.key] ?? "").trim() !== "");
    const canContinue = allVarsFilled &&
        name.trim() !== "" &&
        audience.trim() !== "" &&
        !isLoading;
    return (_jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: preset.variables.length > 0
                    ? `Enter your ${preset.label} details to auto-populate the OIDC configuration.`
                    : `${preset.label} configuration is fully automatic — just provide a name and audience.` }), preset.variables.map((v) => (_jsx(FieldInput, { id: `stgm-idp-var-${v.key}`, label: v.label, value: vars[v.key] ?? "", onChange: (val) => onVarChange(v.key, val), placeholder: v.placeholder, hint: v.hint, disabled: isLoading, type: v.type, options: v.options }, v.key))), _jsx("hr", { className: "border-border-muted" }), _jsx(FieldInput, { id: "stgm-idp-wiz-name", label: "Display name", value: name, onChange: onNameChange, placeholder: "e.g., Acme Corp SSO", hint: "Human-readable name shown in the UI", disabled: isLoading }), _jsx(FieldInput, { id: "stgm-idp-wiz-audience", label: "Expected audience", value: audience, onChange: onAudienceChange, placeholder: "stigmer-api", hint: "The aud claim value expected in JWTs from this provider", disabled: isLoading }), discoveryError && (_jsx("p", { className: "text-destructive text-[0.65rem]", role: "alert", children: getUserMessage(discoveryError) })), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsxs("button", { type: "button", onClick: onContinue, disabled: !canContinue, 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: [isLoading && _jsx(SpinnerIcon, {}), "Continue"] }), _jsx(TextButton, { onClick: onBack, disabled: isLoading, children: "Back" }), onCancel && (_jsx(CancelButton, { onClick: onCancel, disabled: isLoading }))] })] }));
}
// ---------------------------------------------------------------------------
// Review step (step 3)
// ---------------------------------------------------------------------------
function ReviewStep({ discoveryFailed, jwksUri, onJwksUriChange, issuers, onIssuersChange, userinfoEndpoint, onUserinfoEndpointChange, isSso, onIsSsoChange, oidcClientId, onOidcClientIdChange, autoProvision, onAutoProvisionChange, autoGrant, onAutoGrantChange, autoGrantRole, onAutoGrantRoleChange, tenantOrgClaim, onTenantOrgClaimChange, isCreating, createError, onBack, onSubmit, onCancel, }) {
    const canSubmit = jwksUri.trim() !== "" &&
        issuers.trim() !== "" &&
        (!isSso || oidcClientId.trim() !== "") &&
        !isCreating;
    return (_jsxs("form", { onSubmit: onSubmit, className: "space-y-3", children: [discoveryFailed && (_jsx("div", { className: "rounded-md border border-warning/30 bg-warning/5 px-3 py-2 text-xs text-warning-foreground", role: "alert", children: "Auto-discovery could not reach the provider. Enter the configuration manually below." })), _jsx("p", { className: "text-muted-foreground text-xs", children: "Review the OIDC configuration. All fields are editable." }), _jsx(FieldInput, { id: "stgm-idp-wiz-jwks", label: "JWKS URI", value: jwksUri, onChange: onJwksUriChange, placeholder: "https://example.com/.well-known/jwks.json", disabled: isCreating, required: true }), _jsx(FieldInput, { id: "stgm-idp-wiz-issuers", label: "Allowed issuers", value: issuers, onChange: onIssuersChange, placeholder: "https://issuer.example.com/", hint: "Comma-separated list of trusted JWT issuer values", disabled: isCreating, required: true }), _jsx(FieldInput, { id: "stgm-idp-wiz-userinfo", label: "Userinfo endpoint", value: userinfoEndpoint, onChange: onUserinfoEndpointChange, placeholder: "https://example.com/userinfo", hint: "Optional \u2014 used to fetch user profile data during token exchange", disabled: isCreating }), _jsx(ToggleSwitch, { checked: isSso, onChange: onIsSsoChange, label: "SSO provider", disabled: isCreating }), isSso && (_jsx(FieldInput, { id: "stgm-idp-wiz-client-id", label: "OIDC client ID", value: oidcClientId, onChange: onOidcClientIdChange, placeholder: "public-client-id", hint: "Client ID for the PKCE-based Authorization Code flow", disabled: isCreating, required: true })), _jsx(JitProvisioningSection, { isSso: isSso, autoProvision: autoProvision, onAutoProvisionChange: onAutoProvisionChange, autoGrant: autoGrant, onAutoGrantChange: onAutoGrantChange, autoGrantRole: autoGrantRole, onAutoGrantRoleChange: onAutoGrantRoleChange, tenantOrgClaim: tenantOrgClaim, onTenantOrgClaimChange: onTenantOrgClaimChange, disabled: isCreating }), createError && (_jsx("p", { className: "text-destructive text-[0.65rem]", role: "alert", children: getUserMessage(createError) })), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsxs("button", { type: "submit", disabled: !canSubmit, 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: [isCreating && _jsx(SpinnerIcon, {}), "Create identity provider"] }), _jsx(TextButton, { onClick: onBack, disabled: isCreating, children: "Back" }), onCancel && (_jsx(CancelButton, { onClick: onCancel, disabled: isCreating }))] })] }));
}
// ---------------------------------------------------------------------------
// Success step (step 4)
// ---------------------------------------------------------------------------
function SuccessStep({ identityProvider, org, isSso, autoProvision, autoGrant, autoGrantRole, onDone, }) {
    const displayName = identityProvider.spec?.displayName ||
        identityProvider.metadata?.name ||
        "Identity provider";
    const roleName = autoGrantRole !== IamRole.iam_role_unspecified
        ? IamRole[autoGrantRole]
        : "viewer";
    return (_jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "rounded-md border border-primary/30 bg-primary-subtle px-3 py-2.5", children: _jsxs("p", { className: "text-xs font-medium text-foreground", children: [displayName, " created successfully"] }) }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-medium text-foreground", children: "What happens next" }), isSso ? (_jsxs("p", { className: "text-[0.65rem] text-muted-foreground", children: ["Users can sign in via SSO at", " ", _jsxs("span", { className: "font-mono text-foreground", children: ["/login?org=", org] }), ". Accounts are auto-provisioned and granted the", " ", _jsx("span", { className: "font-medium text-foreground", children: "viewer" }), " role on this organization."] })) : autoProvision && autoGrant ? (_jsxs("p", { className: "text-[0.65rem] text-muted-foreground", children: ["Users authenticating with JWTs from this provider will be automatically provisioned and granted the", " ", _jsx("span", { className: "font-medium text-foreground", children: roleName }), " role on this organization. No additional setup is required."] })) : autoProvision ? (_jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: "Accounts are auto-provisioned on first authentication, but no organization role is granted automatically. Use the Members page to grant access." })) : (_jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: "The trust relationship is configured. Accounts must be created manually before users can authenticate." })), _jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: "To verify the setup, have a user authenticate with a JWT from this provider and confirm they can access the organization's resources." })] }), _jsx("button", { type: "button", onClick: onDone, 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"), children: "Done" })] }));
}
// ---------------------------------------------------------------------------
// Shared primitives
// ---------------------------------------------------------------------------
function FieldInput({ id, label, value, onChange, placeholder, hint, disabled, required, type = "text", options, }) {
    return (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: id, className: "text-xs font-medium text-foreground", children: label }), type === "select" && options ? (_jsx("select", { id: id, value: value, onChange: (e) => onChange(e.target.value), disabled: disabled, 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: options.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value))) })) : (_jsx("input", { id: id, type: "text", 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 }))] }));
}
// ---------------------------------------------------------------------------
// JIT provisioning section
// ---------------------------------------------------------------------------
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" },
];
function JitProvisioningSection({ isSso, autoProvision, onAutoProvisionChange, autoGrant, onAutoGrantChange, autoGrantRole, onAutoGrantRoleChange, tenantOrgClaim, onTenantOrgClaimChange, disabled, }) {
    if (isSso) {
        return (_jsx("div", { className: "rounded-md border border-border-muted bg-muted-faint px-3 py-2", children: _jsxs("p", { className: "text-[0.65rem] text-muted-foreground", children: ["SSO providers automatically provision accounts and grant the", " ", _jsx("span", { className: "font-medium text-foreground", children: "viewer" }), " role on the owning organization. JIT provisioning settings are not applicable."] }) }));
    }
    return (_jsxs("fieldset", { className: "space-y-2.5", disabled: disabled, children: [_jsx("hr", { className: "border-border-muted" }), _jsx("legend", { className: "text-xs font-medium text-foreground", children: "JIT provisioning" }), _jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: "Configure automatic account creation and role assignment for users authenticating with this provider." }), _jsx(ToggleSwitch, { checked: autoProvision, onChange: onAutoProvisionChange, label: "Auto-provision accounts", hint: "Create a federated account automatically on first authentication", disabled: disabled }), _jsx(ToggleSwitch, { checked: autoGrant, onChange: onAutoGrantChange, label: "Auto-grant on organization", hint: "Grant a role on the owning organization when an account is provisioned", disabled: disabled || !autoProvision }), autoGrant && (_jsxs(_Fragment, { children: [_jsx(FieldInput, { id: "stgm-idp-wiz-grant-role", label: "Auto-grant role", value: String(autoGrantRole), onChange: (v) => onAutoGrantRoleChange(Number(v)), placeholder: "", hint: "Role granted automatically \u2014 org admins can upgrade later", disabled: disabled, type: "select", options: JIT_ROLE_OPTIONS }), _jsx(FieldInput, { id: "stgm-idp-wiz-tenant-claim", label: "Tenant org claim", value: tenantOrgClaim, onChange: onTenantOrgClaimChange, placeholder: "e.g., org_id", hint: "JWT claim name that maps to a platform-managed organization (max 256 chars)", disabled: disabled })] }))] }));
}
// ---------------------------------------------------------------------------
// Toggle switch
// ---------------------------------------------------------------------------
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 }))] }));
}
function TextButton({ onClick, disabled, children, }) {
    return (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, 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: children }));
}
function CancelButton({ onClick, disabled, }) {
    return (_jsx(TextButton, { onClick: onClick, disabled: disabled, children: "Cancel" }));
}
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=IdentityProviderWizard.js.map