import { logEvent } from '../../security/audit.js';
import { getClientIp } from '../../security/client-ip.js';
import { getActuateConfig } from '../../config/runtime.js';
import { guardedDb } from '../guarded-db.js';
import { json, errorResponse, internalError, hasModel, requireAuth, requireAdminScope, emailTestLimiter, checkRateLimitAsync, } from '../route-helpers.js';
export function registerEmailSettingsRoutes(router) {
    const db = guardedDb;
    // ---------------------------------------------------------------------------
    // Settings > Email — transactional email provider configuration.
    // Backed by the `__email_config__` document (see `../email/settings-store.ts`).
    // ADMIN-gated. API keys / SMTP passwords are encrypted at rest, NEVER returned.
    // ---------------------------------------------------------------------------
    router.get('/email/settings', async (request) => {
        try {
            const auth = await requireAuth(request);
            if (auth.error)
                return auth.error;
            const adminErr = requireAdminScope(auth.session);
            if (adminErr)
                return adminErr;
            const { getEmailConfig, toPublicEmailConfig, detectEnvEmailProvider } = await import('../../email/settings-store.js');
            const { getEmailProviderFactory, getRegisteredEmailSender } = await import('../../email/sender.js');
            const config = await getEmailConfig(db());
            return json({
                data: {
                    settings: toPublicEmailConfig(config),
                    /** Provider configured via env vars (informational; DB settings win). */
                    envProvider: detectEnvEmailProvider(),
                    /** Whether plugin-email registered its factory (required for DB-configured sends). */
                    factoryAvailable: Boolean(getEmailProviderFactory()),
                    /** Whether an env-configured sender is registered as fallback. */
                    envSenderActive: Boolean(getRegisteredEmailSender()),
                    /** A platform adapter in code takes precedence over everything. */
                    platformAdapter: Boolean(getActuateConfig()?.platform?.email),
                },
            });
        }
        catch (err) {
            return internalError(err, 'email/settings GET');
        }
    });
    router.put('/email/settings', async (request) => {
        try {
            const auth = await requireAuth(request);
            if (auth.error)
                return auth.error;
            const adminErr = requireAdminScope(auth.session);
            if (adminErr)
                return adminErr;
            const body = (await request.json().catch(() => null));
            if (!body || typeof body !== 'object') {
                return errorResponse('Request body must be an object', 400);
            }
            const { getEmailConfig, putEmailConfig, toPublicEmailConfig, validateEmailSettingsInput, encryptEmailSecret, isEmailProviderKey, detectEnvEmailProvider, } = await import('../../email/settings-store.js');
            const { clearEmailSenderCache } = await import('../../email/resolve.js');
            const current = await getEmailConfig(db());
            // Keeping an existing key only makes sense while staying on the same
            // provider — switching providers must not silently reuse the old secret.
            const sameProvider = isEmailProviderKey(body.provider) && body.provider === current.provider;
            const validationError = validateEmailSettingsInput(body, {
                hasApiKey: sameProvider && Boolean(current.apiKeyEncrypted),
            });
            if (validationError)
                return errorResponse(validationError, 400);
            // Clearing the configuration (provider: null) wipes everything,
            // including stored secrets.
            if (body.provider === null) {
                const saved = await putEmailConfig(db(), { provider: null }, auth.session.userId);
                clearEmailSenderCache();
                try {
                    await logEvent({
                        event: 'update_email_settings',
                        userId: auth.session.userId,
                        ipAddress: getClientIp(request),
                        details: { provider: null, source: 'settings.email' },
                    });
                }
                catch {
                    /* never block on audit */
                }
                return json({
                    data: { settings: toPublicEmailConfig(saved), envProvider: detectEnvEmailProvider() },
                });
            }
            const provider = body.provider;
            // Secrets: undefined = keep existing (same provider only), ''/null = clear,
            // string = encrypt + replace.
            let apiKeyEncrypted = sameProvider ? current.apiKeyEncrypted : undefined;
            let apiKeyLast4 = sameProvider ? current.apiKeyLast4 : undefined;
            let keyChanged = false;
            if (body.apiKey !== undefined) {
                if (body.apiKey === null || body.apiKey === '') {
                    apiKeyEncrypted = undefined;
                    apiKeyLast4 = undefined;
                    keyChanged = true;
                }
                else if (typeof body.apiKey === 'string' && body.apiKey.trim()) {
                    const enc = await encryptEmailSecret(body.apiKey.trim());
                    apiKeyEncrypted = enc.encrypted;
                    apiKeyLast4 = enc.last4;
                    keyChanged = true;
                }
            }
            let smtpPassEncrypted = sameProvider ? current.smtpPassEncrypted : undefined;
            let passChanged = false;
            if (body.smtpPass !== undefined) {
                if (body.smtpPass === null || body.smtpPass === '') {
                    smtpPassEncrypted = undefined;
                    passChanged = true;
                }
                else if (typeof body.smtpPass === 'string' && body.smtpPass.trim()) {
                    smtpPassEncrypted = (await encryptEmailSecret(body.smtpPass)).encrypted;
                    passChanged = true;
                }
            }
            const next = {
                provider,
                from: typeof body.from === 'string' ? body.from.trim() : undefined,
                apiKeyEncrypted,
                apiKeyLast4,
                channel: provider === 'smtpcom' && typeof body.channel === 'string' && body.channel.trim()
                    ? body.channel.trim()
                    : undefined,
                region: provider === 'ses' && typeof body.region === 'string' ? body.region.trim() : undefined,
                host: provider === 'smtp' && typeof body.host === 'string' ? body.host.trim() : undefined,
                port: provider === 'smtp' && typeof body.port === 'number' && Number.isInteger(body.port)
                    ? body.port
                    : undefined,
                secure: provider === 'smtp' && typeof body.secure === 'boolean' ? body.secure : undefined,
                smtpUser: provider === 'smtp' && typeof body.smtpUser === 'string' && body.smtpUser.trim()
                    ? body.smtpUser.trim()
                    : undefined,
                smtpPassEncrypted: provider === 'smtp' ? smtpPassEncrypted : undefined,
                // Changing the config invalidates the previous test result.
                lastTestStatus: undefined,
                lastTestedAt: undefined,
                lastTestError: undefined,
            };
            const saved = await putEmailConfig(db(), next, auth.session.userId);
            clearEmailSenderCache();
            try {
                await logEvent({
                    event: 'update_email_settings',
                    userId: auth.session.userId,
                    ipAddress: getClientIp(request),
                    // Config metadata only — never key material.
                    details: {
                        provider,
                        from: next.from ?? null,
                        keyChanged: keyChanged || passChanged,
                        source: 'settings.email',
                    },
                });
            }
            catch {
                /* never block on audit */
            }
            return json({
                data: { settings: toPublicEmailConfig(saved), envProvider: detectEnvEmailProvider() },
            });
        }
        catch (err) {
            return internalError(err, 'email/settings PUT');
        }
    });
    router.post('/email/settings/test', async (request) => {
        try {
            const auth = await requireAuth(request);
            if (auth.error)
                return auth.error;
            const adminErr = requireAdminScope(auth.session);
            if (adminErr)
                return adminErr;
            if (!(await checkRateLimitAsync(emailTestLimiter, `email-test:${auth.session.userId}`))) {
                return errorResponse('Too many test emails. Please try again later.', 429);
            }
            const d = db();
            // The test recipient is ALWAYS the signed-in admin's own address — never
            // a caller-supplied one — so this endpoint can't be used to spam others.
            if (!hasModel(d, 'user')) {
                return errorResponse('User model unavailable; cannot determine recipient.', 500);
            }
            const user = await d.user.findUnique({
                where: { id: auth.session.userId },
                select: { email: true, name: true },
            });
            if (!user?.email) {
                return errorResponse('Your account has no email address to send the test to.', 400);
            }
            const { resolveEmailSenderAsync, clearEmailSenderCache } = await import('../../email/resolve.js');
            const { getEmailConfig, putEmailConfig } = await import('../../email/settings-store.js');
            clearEmailSenderCache(); // always test the freshest configuration
            const sender = await resolveEmailSenderAsync(d);
            if (!sender) {
                return errorResponse('No email provider is configured. Save provider settings (or set env vars) first.', 400);
            }
            let success = false;
            let errorMessage = null;
            try {
                await sender.send({
                    to: user.email,
                    subject: 'Actuate CMS test email',
                    html: `<div style="font-family:system-ui,sans-serif;color:#111;max-width:640px"><p style="font-size:15px">This is a test email from your Actuate CMS email settings${user.name ? `, requested by ${user.name}` : ''}. If you received it, your provider is configured correctly.</p></div>`,
                    text: 'This is a test email from your Actuate CMS email settings. If you received it, your provider is configured correctly.',
                });
                success = true;
            }
            catch (err) {
                errorMessage = err instanceof Error ? err.message : 'Send failed';
            }
            // Record the outcome on the config doc (best-effort) so the UI can show
            // "last tested" state across sessions. Skip when only env config exists.
            try {
                const config = await getEmailConfig(d);
                if (config.provider) {
                    await putEmailConfig(d, {
                        ...config,
                        lastTestStatus: success ? 'success' : 'failed',
                        lastTestedAt: new Date().toISOString(),
                        lastTestError: errorMessage ?? undefined,
                    }, auth.session.userId);
                }
            }
            catch {
                /* recording the result must not mask the send outcome */
            }
            try {
                await logEvent({
                    event: 'test_email_settings',
                    userId: auth.session.userId,
                    ipAddress: getClientIp(request),
                    details: { success, source: 'settings.email' },
                });
            }
            catch {
                /* never block on audit */
            }
            if (!success) {
                return errorResponse(errorMessage ?? 'Test send failed', 502);
            }
            return json({ data: { success: true, sentTo: user.email } });
        }
        catch (err) {
            return internalError(err, 'email/settings test');
        }
    });
}
//# sourceMappingURL=email-settings.js.map