import { logEvent } from '../../security/audit.js';
import { createPreviewAdapter } from '../../preview/index.js';
import { createPreviewStreamResponse } from '../../preview/sse-stream.js';
import { guardedDb } from '../guarded-db.js';
import { json, errorResponse, internalError, getSessionSecret, requireAuth, } from '../route-helpers.js';
export function registerPreviewRoutes(router) {
    const db = guardedDb;
    // ---------------------------------------------------------------------------
    // Preview routes
    // ---------------------------------------------------------------------------
    router.post('/preview/token', async (request) => {
        try {
            const auth = await requireAuth(request);
            if (auth.error)
                return auth.error;
            const body = (await request.json());
            if (!body.collection || !body.documentId) {
                return errorResponse('collection and documentId are required', 400);
            }
            // Verify the document actually exists so we don't issue tokens for
            // hypothetical ids — a leaked token would otherwise silently work
            // once a doc with that id appeared.
            const doc = await db().document.findFirst({
                where: { id: body.documentId, collection: body.collection, deletedAt: null },
                select: { id: true, slug: true },
            });
            if (!doc)
                return errorResponse('Document not found', 404);
            const preview = createPreviewAdapter(getSessionSecret(), db());
            const session = await preview.createPreviewSession(body.collection, body.documentId, {
                ttlSeconds: body.ttlSeconds,
                issuedBy: auth.session.userId,
            });
            await logEvent({
                event: 'preview_token_issued',
                userId: auth.session.userId,
                details: {
                    collection: body.collection,
                    documentId: body.documentId,
                    expiresAt: session.expiresAt.toISOString(),
                },
            });
            return json({
                data: {
                    token: session.token,
                    expiresAt: session.expiresAt,
                    slug: doc.slug,
                },
            });
        }
        catch (err) {
            return internalError(err, 'create preview token');
        }
    });
    router.get('/preview/:collection/:id', async (request, params) => {
        try {
            const url = new URL(request.url);
            const token = url.searchParams.get('token');
            if (!token)
                return errorResponse('Preview token required', 401);
            const preview = createPreviewAdapter(getSessionSecret(), db());
            const session = await preview.validatePreviewToken(token);
            if (!session)
                return errorResponse('Invalid or expired preview token', 401);
            if (session.collection !== params.collection || session.documentId !== params.id) {
                return errorResponse('Token does not match requested resource', 403);
            }
            const data = await preview.getPreviewData(session);
            if (!data)
                return errorResponse('Document not found', 404);
            return json({ data });
        }
        catch (err) {
            return internalError(err, 'fetch preview data');
        }
    });
    /**
     * Server-Sent Events stream for live preview. The admin's `LivePreview`
     * panel opens an `EventSource('/api/cms/preview/stream?token=...')` and
     * relays every `event: update` frame to the previewed iframe through
     * `postMessage`. Token-based auth (instead of cookies) because
     * `EventSource` cannot send arbitrary headers.
     *
     * Emits:
     *   - `event: ready` once on connection (handshake).
     *   - `event: update` whenever the underlying draft document is updated
     *     (see `PUT /collections/:slug/:id` for the emit site).
     *   - `: heartbeat\n\n` keepalive comments every 25 s so proxies don't
     *     reap idle connections.
     *
     * Closes cleanly after 4 minutes so platform idle caps don't terminate
     * the connection mid-event; EventSource will auto-reconnect.
     */
    router.get('/preview/stream', async (request) => {
        try {
            const url = new URL(request.url);
            const token = url.searchParams.get('token');
            if (!token)
                return errorResponse('Preview token required', 401);
            const preview = createPreviewAdapter(getSessionSecret(), db());
            const session = await preview.validatePreviewToken(token);
            if (!session)
                return errorResponse('Invalid or expired preview token', 401);
            return createPreviewStreamResponse(session);
        }
        catch (err) {
            return internalError(err, 'open preview stream');
        }
    });
}
//# sourceMappingURL=preview.js.map