import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { NextRequest, NextResponse } from 'next/server'

function createCronRequest(
  url = 'https://example.com/api/cron/test',
  authHeader?: string,
  extraHeaders: Record<string, string> = {},
): NextRequest {
  const headers = new Headers(extraHeaders)
  if (authHeader) {
    headers.set('authorization', authHeader)
  }
  return new NextRequest(url, { headers })
}

describe('cron auth and coordination', () => {
  beforeEach(() => {
    vi.resetModules()
    vi.stubEnv('REDIS_ENABLED', 'false')
    vi.stubEnv('CRON_SECRET', 'top-secret-token')
  })

  afterEach(() => {
    vi.unstubAllEnvs()
  })

  it('denies requests when CRON_SECRET is missing', async () => {
    vi.stubEnv('CRON_SECRET', '')
    const { requireCronAuth } = await import('@/lib/security/cron-auth')

    const response = requireCronAuth(createCronRequest())

    expect(response).not.toBeNull()
    expect(response?.status).toBe(503)
  })

  it('denies requests with missing bearer header', async () => {
    const { requireCronAuth } = await import('@/lib/security/cron-auth')

    const response = requireCronAuth(createCronRequest())

    expect(response).not.toBeNull()
    expect(response?.status).toBe(401)
  })

  it('allows requests with valid bearer header', async () => {
    const { requireCronAuth } = await import('@/lib/security/cron-auth')

    const response = requireCronAuth(
      createCronRequest('https://example.com/api/cron/test', 'Bearer top-secret-token'),
    )

    expect(response).toBeNull()
  })

  it('ignores duplicate idempotency-key requests', async () => {
    const { withCronExecution, resetCronCoordinationStateForTests } = await import(
      '@/lib/security/cron-coordination'
    )
    resetCronCoordinationStateForTests()

    const req1 = createCronRequest(
      'https://example.com/api/cron/test?idempotencyKey=abc',
      'Bearer top-secret-token',
    )
    const req2 = createCronRequest(
      'https://example.com/api/cron/test?idempotencyKey=abc',
      'Bearer top-secret-token',
    )

    const first = await withCronExecution(req1, { endpoint: 'test-cron' }, async () =>
      NextResponse.json({ ok: true }),
    )
    const second = await withCronExecution(req2, { endpoint: 'test-cron' }, async () =>
      NextResponse.json({ ok: true }),
    )

    expect(first.status).toBe(200)
    expect(second.status).toBe(202)
  })

  it('enforces execution lock per endpoint', async () => {
    const { withCronExecution, resetCronCoordinationStateForTests } = await import(
      '@/lib/security/cron-coordination'
    )
    resetCronCoordinationStateForTests()

    let releaseHandler: () => void = () => {}
    const firstRun = withCronExecution(
      createCronRequest('https://example.com/api/cron/test', 'Bearer top-secret-token'),
      { endpoint: 'locked-cron', lockTtlMs: 120000 },
      async () =>
        new Promise<NextResponse>((resolve) => {
          releaseHandler = () => resolve(NextResponse.json({ ok: true }))
        }),
    )

    const second = await withCronExecution(
      createCronRequest('https://example.com/api/cron/test', 'Bearer top-secret-token'),
      { endpoint: 'locked-cron', lockTtlMs: 120000 },
      async () => NextResponse.json({ ok: true }),
    )

    expect(second.status).toBe(423)

    releaseHandler()
    const first = await firstRun
    expect(first.status).toBe(200)
  })
})
