'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import * as Dialog from '@radix-ui/react-dialog';
import { adminPortalContainer } from '../lib/portal-container.js';
import { Copy, KeyRound, Loader2, Plus, Shield, Trash2, AlertTriangle, Eye, EyeOff, } from 'lucide-react';
import { useState } from 'react';
import { toast } from 'sonner';
import { useApiData } from '../lib/useApiData.js';
import { cmsApi } from '../lib/api.js';
import { SettingsCard } from './settings/components.js';
const DIALOG_INPUT_CLASS = 'w-full rounded-md border border-border bg-input-background px-3 py-2 text-base text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none';
function formatScopes(scopes) {
    if (scopes.admin)
        return 'Full admin';
    const parts = [];
    if (scopes.collections?.length) {
        const cols = scopes.collections.includes('*')
            ? 'all collections'
            : scopes.collections.join(', ');
        const acts = scopes.actions?.join('/') ?? 'read';
        parts.push(`${acts} on ${cols}`);
    }
    if (scopes.globals?.length)
        parts.push(`globals: ${scopes.globals.join(', ')}`);
    if (scopes.media)
        parts.push('media');
    if (scopes.pageBuilder)
        parts.push('pageBuilder');
    return parts.length > 0 ? parts.join(' · ') : 'No scopes';
}
function formatDate(value) {
    if (!value)
        return '—';
    try {
        return new Date(value).toLocaleString();
    }
    catch {
        return value;
    }
}
export function ApiKeys({ embedded = false } = {}) {
    const { data, loading, error, refetch } = useApiData('/api-keys');
    const [showCreate, setShowCreate] = useState(false);
    const [createdKey, setCreatedKey] = useState(null);
    const keys = data ?? [];
    const rootPadding = embedded ? '' : 'p-4 sm:p-6';
    const handleRevoke = async (id, name) => {
        if (!confirm(`Revoke API key "${name}"? This cannot be undone.`))
            return;
        const password = prompt('Confirm your password to revoke this API key:');
        if (!password)
            return;
        const res = await cmsApi(`/api-keys/${id}`, {
            method: 'DELETE',
            headers: { 'x-reauth-password': password },
        });
        if (res.error) {
            toast.error(res.error);
        }
        else {
            toast.success('API key revoked');
            refetch();
        }
    };
    if (loading) {
        return (_jsx("div", { className: `flex h-64 items-center justify-center ${embedded ? '' : 'p-4 sm:p-6'}`, children: _jsx(Loader2, { className: "text-brand h-6 w-6 animate-spin" }) }));
    }
    return (_jsxs("div", { className: rootPadding, children: [_jsxs(SettingsCard, { headingLevel: "h2", title: "API Keys", description: _jsxs(_Fragment, { children: ["Long-lived credentials for programmatic access. Use the", ' ', _jsx("code", { className: "bg-muted rounded px-1 py-0.5 text-xs", children: "Authorization: Bearer" }), ' ', "header instead of session cookies. API key requests skip CSRF."] }), actions: _jsxs("button", { type: "button", onClick: () => setShowCreate(true), className: "bg-brand text-brand-foreground inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90", children: [_jsx(Plus, { size: 16, "aria-hidden": "true" }), "New API Key"] }), children: [error && (_jsxs("div", { role: "alert", className: "border-destructive/30 bg-destructive/10 text-destructive mb-4 flex items-center gap-3 rounded-lg border p-3 text-sm", children: [_jsx(AlertTriangle, { size: 20, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { className: "flex-1", children: error }), _jsx("button", { onClick: refetch, className: "border-destructive/40 rounded-md border px-3 py-1 transition-colors hover:opacity-80", children: "Retry" })] })), keys.length === 0 ? (_jsxs("div", { className: "py-10 text-center", children: [_jsx(KeyRound, { className: "text-muted-foreground mx-auto mb-3 h-8 w-8", "aria-hidden": "true" }), _jsx("p", { className: "text-foreground mb-1 text-sm font-medium", children: "No API keys yet" }), _jsx("p", { className: "text-muted-foreground mb-4 text-sm", children: "Create one to let AI agents, CI jobs, or external integrations call the CMS API." }), _jsxs("button", { type: "button", onClick: () => setShowCreate(true), className: "bg-brand text-brand-foreground inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90", children: [_jsx(Plus, { size: 16, "aria-hidden": "true" }), "Create your first API key"] })] })) : (_jsx("div", { className: "border-border overflow-hidden rounded-lg border", children: _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "border-border bg-muted/50 border-b", children: _jsxs("tr", { children: [_jsx("th", { className: "text-muted-foreground px-4 py-2 text-left text-xs font-medium", children: "Name" }), _jsx("th", { className: "text-muted-foreground px-4 py-2 text-left text-xs font-medium", children: "Token" }), _jsx("th", { className: "text-muted-foreground px-4 py-2 text-left text-xs font-medium", children: "Scopes" }), _jsx("th", { className: "text-muted-foreground px-4 py-2 text-left text-xs font-medium", children: "Last used" }), _jsx("th", { className: "text-muted-foreground px-4 py-2 text-left text-xs font-medium", children: "Expires" }), _jsx("th", { className: "text-muted-foreground px-4 py-2 text-left text-xs font-medium", children: "Status" }), _jsx("th", { className: "px-4 py-2" })] }) }), _jsx("tbody", { className: "divide-border divide-y", children: keys.map((k) => {
                                            const revoked = !!k.revokedAt;
                                            const expired = k.expiresAt && new Date(k.expiresAt).getTime() < Date.now();
                                            return (_jsxs("tr", { className: revoked || expired ? 'opacity-60' : undefined, children: [_jsxs("td", { className: "px-4 py-3 text-sm", children: [_jsx("div", { className: "text-foreground font-medium", children: k.name }), k.user && (_jsxs("div", { className: "text-muted-foreground text-xs", children: ["created by ", k.user.name ?? k.user.email] }))] }), _jsxs("td", { className: "text-muted-foreground px-4 py-3 font-mono text-sm", children: [k.keyPrefix, "\u2026"] }), _jsx("td", { className: "text-foreground max-w-xs px-4 py-3 text-sm", children: formatScopes(k.scopes) }), _jsx("td", { className: "text-muted-foreground px-4 py-3 text-sm", children: formatDate(k.lastUsedAt) }), _jsx("td", { className: "text-muted-foreground px-4 py-3 text-sm", children: formatDate(k.expiresAt) }), _jsx("td", { className: "px-4 py-3", children: revoked ? (_jsx("span", { className: "bg-destructive/10 text-destructive inline-flex rounded-full px-2 py-0.5 text-xs font-medium", children: "Revoked" })) : expired ? (_jsx("span", { className: "bg-warning/10 text-warning inline-flex rounded-full px-2 py-0.5 text-xs font-medium", children: "Expired" })) : (_jsx("span", { className: "bg-success/10 text-success inline-flex rounded-full px-2 py-0.5 text-xs font-medium", children: "Active" })) }), _jsx("td", { className: "px-4 py-3 text-right", children: !revoked && (_jsx("button", { type: "button", onClick: () => handleRevoke(k.id, k.name), className: "hover:bg-destructive/10 rounded p-1.5 transition-colors", "aria-label": `Revoke ${k.name}`, title: "Revoke", children: _jsx(Trash2, { className: "text-destructive h-4 w-4", "aria-hidden": "true" }) })) })] }, k.id));
                                        }) })] }) }) }))] }), _jsx(CreateApiKeyDialog, { open: showCreate, onClose: () => setShowCreate(false), onCreated: (created) => {
                    setShowCreate(false);
                    setCreatedKey(created);
                    refetch();
                } }), createdKey && _jsx(RevealKeyDialog, { created: createdKey, onClose: () => setCreatedKey(null) })] }));
}
function CreateApiKeyDialog({ open, onClose, onCreated }) {
    const [name, setName] = useState('');
    const [preset, setPreset] = useState('content');
    const [pageBuilder, setPageBuilder] = useState(true);
    const [media, setMedia] = useState(true);
    const [expiresInDays, setExpiresInDays] = useState('');
    const [password, setPassword] = useState('');
    const [submitting, setSubmitting] = useState(false);
    function buildScopes() {
        if (preset === 'admin')
            return { admin: true };
        if (preset === 'readonly') {
            return {
                collections: ['*'],
                actions: ['read'],
                globals: ['*'],
                media: false,
                pageBuilder: false,
            };
        }
        if (preset === 'content') {
            return {
                collections: ['*'],
                actions: ['read', 'create', 'update'],
                globals: ['*'],
                media,
                pageBuilder,
            };
        }
        return {
            collections: ['*'],
            actions: ['read'],
            media,
            pageBuilder,
        };
    }
    async function handleSubmit(e) {
        e.preventDefault();
        if (!name.trim())
            return toast.error('Name is required');
        if (!password)
            return toast.error('Password confirmation is required');
        setSubmitting(true);
        try {
            const scopes = buildScopes();
            const body = { name: name.trim(), scopes };
            const days = parseInt(expiresInDays, 10);
            if (!isNaN(days) && days > 0) {
                body.expiresAt = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString();
            }
            const res = await cmsApi('/api-keys', {
                method: 'POST',
                headers: { 'x-reauth-password': password, 'Content-Type': 'application/json' },
                body: JSON.stringify(body),
            });
            if (res.error || !res.data) {
                toast.error(res.error ?? 'Failed to create API key');
                return;
            }
            const { key, ...record } = res.data;
            onCreated({ key, record: record });
            setName('');
            setPassword('');
            setExpiresInDays('');
        }
        finally {
            setSubmitting(false);
        }
    }
    return (_jsx(Dialog.Root, { open: open, onOpenChange: (o) => !o && onClose(), children: _jsxs(Dialog.Portal, { container: adminPortalContainer(), children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 z-40 bg-black/40" }), _jsxs(Dialog.Content, { className: "border-border bg-card fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border p-6 shadow-xl", children: [_jsxs(Dialog.Title, { className: "text-card-foreground mb-4 flex items-center gap-2 text-lg font-medium", children: [_jsx(Shield, { className: "text-brand h-5 w-5", "aria-hidden": "true" }), "New API Key"] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "apikey-name", className: "text-foreground mb-1 block text-sm font-medium", children: "Name" }), _jsx("input", { id: "apikey-name", type: "text", value: name, onChange: (e) => setName(e.target.value), placeholder: "e.g. AI agent \u2014 production", className: DIALOG_INPUT_CLASS, required: true, maxLength: 100 })] }), _jsxs("div", { children: [_jsx("span", { className: "text-foreground mb-2 block text-sm font-medium", children: "Preset" }), _jsx("div", { className: "grid grid-cols-2 gap-2", children: ['content', 'readonly', 'admin', 'custom'].map((p) => (_jsxs("button", { type: "button", onClick: () => setPreset(p), "aria-pressed": preset === p, className: `rounded-md border px-3 py-2 text-left text-sm transition-colors ${preset === p
                                                    ? 'border-brand bg-brand/5 text-foreground'
                                                    : 'border-border text-foreground hover:bg-accent'}`, children: [_jsx("div", { className: "font-medium capitalize", children: p }), _jsxs("div", { className: "text-muted-foreground text-xs", children: [p === 'content' && 'Read/create/update content', p === 'readonly' && 'Read-only access', p === 'admin' && 'Full admin access', p === 'custom' && 'Pick capabilities'] })] }, p))) })] }), (preset === 'content' || preset === 'custom') && (_jsxs("div", { className: "border-border bg-muted/50 space-y-2 rounded-md border p-3", children: [_jsxs("label", { className: "text-foreground flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: media, onChange: (e) => setMedia(e.target.checked), className: "accent-brand h-4 w-4" }), "Allow media uploads"] }), _jsxs("label", { className: "text-foreground flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: pageBuilder, onChange: (e) => setPageBuilder(e.target.checked), className: "accent-brand h-4 w-4" }), "Allow AI page generation"] })] })), _jsxs("div", { children: [_jsx("label", { htmlFor: "apikey-expiry", className: "text-foreground mb-1 block text-sm font-medium", children: "Expires in (days)" }), _jsx("input", { id: "apikey-expiry", type: "number", min: 1, placeholder: "Never (leave blank)", value: expiresInDays, onChange: (e) => setExpiresInDays(e.target.value), className: DIALOG_INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "apikey-password", className: "text-foreground mb-1 block text-sm font-medium", children: "Confirm password" }), _jsx("input", { id: "apikey-password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), className: DIALOG_INPUT_CLASS, required: true }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: "Creating an API key is a sensitive action and requires re-authentication." })] }), _jsxs("div", { className: "flex items-center justify-end gap-2 pt-2", children: [_jsx("button", { type: "button", onClick: onClose, className: "border-border text-foreground hover:bg-accent rounded-md border px-4 py-2 text-sm transition-colors", children: "Cancel" }), _jsx("button", { type: "submit", disabled: submitting, className: "bg-brand text-brand-foreground rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90 disabled:opacity-50", children: submitting ? 'Creating…' : 'Create key' })] })] })] })] }) }));
}
function RevealKeyDialog({ created, onClose, }) {
    const [shown, setShown] = useState(false);
    return (_jsx(Dialog.Root, { open: true, onOpenChange: (o) => !o && onClose(), children: _jsxs(Dialog.Portal, { container: adminPortalContainer(), children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 z-40 bg-black/40" }), _jsxs(Dialog.Content, { className: "border-border bg-card fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border p-6 shadow-xl", children: [_jsxs(Dialog.Title, { className: "text-card-foreground mb-2 flex items-center gap-2 text-lg font-medium", children: [_jsx(Shield, { className: "text-success h-5 w-5", "aria-hidden": "true" }), "API key created"] }), _jsx(Dialog.Description, { className: "text-muted-foreground mb-4 text-sm", children: "Copy this key now \u2014 it will not be shown again. Treat it like a password." }), _jsxs("div", { className: "border-warning/30 bg-warning/10 mb-4 flex items-start gap-2 rounded-lg border p-3", children: [_jsx(AlertTriangle, { className: "text-warning mt-0.5 h-4 w-4 shrink-0", "aria-hidden": "true" }), _jsx("p", { className: "text-foreground text-xs", children: "We only store a hash of this key. If you lose it, you'll need to revoke and create a new one." })] }), _jsxs("div", { className: "mb-4 flex items-center gap-2", children: [_jsx("code", { className: "bg-muted text-foreground flex-1 rounded px-3 py-2 font-mono text-sm break-all", children: shown ? created.key : '•'.repeat(Math.min(48, created.key.length)) }), _jsx("button", { type: "button", onClick: () => setShown((s) => !s), className: "border-border text-foreground hover:bg-accent rounded-md border p-2 transition-colors", "aria-label": shown ? 'Hide key' : 'Show key', children: shown ? _jsx(EyeOff, { className: "h-4 w-4" }) : _jsx(Eye, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => {
                                        navigator.clipboard.writeText(created.key);
                                        toast.success('Copied to clipboard');
                                    }, className: "border-border text-foreground hover:bg-accent rounded-md border p-2 transition-colors", "aria-label": "Copy key", children: _jsx(Copy, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "flex justify-end", children: _jsx("button", { type: "button", onClick: onClose, className: "bg-brand text-brand-foreground rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90", children: "I've saved it" }) })] })] }) }));
}
//# sourceMappingURL=ApiKeys.js.map