import { requireCronSecret } from '../cron-auth';

function makeRequest(opts: { url?: string; auth?: string } = {}): Request {
    const url = opts.url ?? 'http://localhost:3005/api/cron';
    const headers = new Headers();
    if (opts.auth) headers.set('authorization', opts.auth);
    return new Request(url, { method: 'GET', headers });
}

describe('requireCronSecret', () => {
    const original = process.env.CRON_SECRET;

    afterEach(() => {
        if (original === undefined) delete process.env.CRON_SECRET;
        else process.env.CRON_SECRET = original;
    });

    it('returns 503 when CRON_SECRET is unset', async () => {
        delete process.env.CRON_SECRET;
        const res = requireCronSecret(makeRequest());
        expect(res).not.toBeNull();
        expect(res!.status).toBe(503);
    });

    it('returns 503 when CRON_SECRET is too short', async () => {
        process.env.CRON_SECRET = 'short';
        const res = requireCronSecret(makeRequest());
        expect(res).not.toBeNull();
        expect(res!.status).toBe(503);
    });

    it('returns 401 when no secret presented', async () => {
        process.env.CRON_SECRET = 'this-is-a-long-enough-secret-1234';
        const res = requireCronSecret(makeRequest());
        expect(res).not.toBeNull();
        expect(res!.status).toBe(401);
    });

    it('returns 401 on wrong secret via query', async () => {
        process.env.CRON_SECRET = 'this-is-a-long-enough-secret-1234';
        const res = requireCronSecret(
            makeRequest({ url: 'http://localhost:3005/api/cron?secret=wrong' })
        );
        expect(res).not.toBeNull();
        expect(res!.status).toBe(401);
    });

    it('returns 401 on wrong secret via header', async () => {
        process.env.CRON_SECRET = 'this-is-a-long-enough-secret-1234';
        const res = requireCronSecret(makeRequest({ auth: 'Bearer wrong' }));
        expect(res).not.toBeNull();
        expect(res!.status).toBe(401);
    });

    it('returns null on correct secret via query', async () => {
        process.env.CRON_SECRET = 'this-is-a-long-enough-secret-1234';
        const res = requireCronSecret(
            makeRequest({
                url:
                    'http://localhost:3005/api/cron?secret=this-is-a-long-enough-secret-1234',
            })
        );
        expect(res).toBeNull();
    });

    it('returns null on correct secret via Bearer header', async () => {
        process.env.CRON_SECRET = 'this-is-a-long-enough-secret-1234';
        const res = requireCronSecret(
            makeRequest({ auth: 'Bearer this-is-a-long-enough-secret-1234' })
        );
        expect(res).toBeNull();
    });

    it('does not leak via length-only comparison', async () => {
        // A 1-char secret matching the first char of the real one should still fail.
        process.env.CRON_SECRET = 'this-is-a-long-enough-secret-1234';
        const res = requireCronSecret(makeRequest({ auth: 'Bearer t' }));
        expect(res).not.toBeNull();
        expect(res!.status).toBe(401);
    });
});
