import { NextResponse } from 'next/server';
import crypto from 'crypto';

/**
 * Shared cron-route authorization.
 *
 * Every /api/cron/* route is internet-reachable when self-hosted behind a
 * reverse proxy. Without CRON_SECRET an attacker can trigger arbitrary
 * monitor probes, force database deletes, or send emails. This helper
 * gives every cron route the same allow-or-deny contract.
 *
 * Accepted forms:
 *   ?secret=<value>
 *   Authorization: Bearer <value>
 *
 * Comparison is timing-safe.
 *
 * Returns a NextResponse to short-circuit the route handler, or null to
 * continue. Usage:
 *
 *   const denied = requireCronSecret(req);
 *   if (denied) return denied;
 */
export function requireCronSecret(req: Request): NextResponse | null {
    const envSecret = process.env.CRON_SECRET;

    if (!envSecret || envSecret.length < 16) {
        return NextResponse.json(
            {
                error: 'cron-disabled',
                message:
                    'CRON_SECRET is not configured on this server. ' +
                    'Set CRON_SECRET to a string of at least 16 characters to enable cron endpoints.',
            },
            { status: 503 }
        );
    }

    const url = new URL(req.url);
    const querySecret = url.searchParams.get('secret');
    const authHeader = req.headers.get('authorization');
    const headerSecret = authHeader?.startsWith('Bearer ')
        ? authHeader.slice('Bearer '.length).trim()
        : null;

    const presented = querySecret ?? headerSecret;
    if (!presented) {
        return NextResponse.json(
            { error: 'unauthorized', message: 'Missing CRON_SECRET' },
            { status: 401 }
        );
    }

    const expected = Buffer.from(envSecret, 'utf8');
    const actual = Buffer.from(presented, 'utf8');
    if (expected.length !== actual.length || !crypto.timingSafeEqual(expected, actual)) {
        return NextResponse.json(
            { error: 'unauthorized', message: 'Invalid CRON_SECRET' },
            { status: 401 }
        );
    }

    return null;
}
