import { it, expect, vi, beforeEach } from 'vitest'
import { makeBrevoAdapter } from './brevo.js'
import { MailProviderError } from './index.js'

const fetchMock = vi.fn()

beforeEach(() => {
  fetchMock.mockReset()
})

it('maps MailMessage to Brevo JSON body and api-key header', async () => {
  fetchMock.mockResolvedValue(
    new Response(JSON.stringify({ messageId: 'br-1' }), { status: 201 }),
  )

  const adapter = makeBrevoAdapter({ apiKey: 'brevo-key', fetchImpl: fetchMock })
  await adapter.send({
    from: 'Sender <from@example.com>',
    to: 'to@example.com',
    replyTo: 'reply@example.com',
    subject: 'Subject',
    html: '<p>Hi</p>',
    text: 'Hi',
  })

  expect(fetchMock).toHaveBeenCalledOnce()
  const [url, init] = fetchMock.mock.calls[0]!
  expect(url).toBe('https://api.brevo.com/v3/smtp/email')
  expect(init?.headers).toMatchObject({
    'api-key': 'brevo-key',
    'content-type': 'application/json',
  })
  expect(JSON.parse(String(init?.body))).toMatchObject({
    sender: { name: 'Sender', email: 'from@example.com' },
    to: [{ email: 'to@example.com' }],
    replyTo: { email: 'reply@example.com' },
    subject: 'Subject',
    htmlContent: '<p>Hi</p>',
    textContent: 'Hi',
  })
})

it('forwards idempotencyKey as the Idempotency-Key header when present', async () => {
  fetchMock.mockResolvedValue(
    new Response(JSON.stringify({ messageId: 'br-idem' }), { status: 201 }),
  )

  const adapter = makeBrevoAdapter({ apiKey: 'brevo-key', fetchImpl: fetchMock })
  await adapter.send({
    from: 'from@example.com',
    to: 'to@example.com',
    subject: 'Subject',
    text: 'Hi',
    idempotencyKey: 'uuid-abc',
  })

  const [, init] = fetchMock.mock.calls[0]!
  expect(init?.headers).toMatchObject({ 'Idempotency-Key': 'uuid-abc' })
})

it('omits the Idempotency-Key header when idempotencyKey is absent', async () => {
  fetchMock.mockResolvedValue(
    new Response(JSON.stringify({ messageId: 'br-noidem' }), { status: 201 }),
  )

  const adapter = makeBrevoAdapter({ apiKey: 'brevo-key', fetchImpl: fetchMock })
  await adapter.send({
    from: 'from@example.com',
    to: 'to@example.com',
    subject: 'Subject',
    text: 'Hi',
  })

  const [, init] = fetchMock.mock.calls[0]!
  expect(init?.headers).not.toHaveProperty('Idempotency-Key')
})

it('maps provider errors to MailProviderError', async () => {
  fetchMock.mockResolvedValue(
    new Response(JSON.stringify({ message: 'invalid' }), { status: 400 }),
  )

  const adapter = makeBrevoAdapter({ apiKey: 'brevo-key', fetchImpl: fetchMock })
  await expect(
    adapter.send({
      from: 'from@example.com',
      to: 'to@example.com',
      subject: 'Subject',
      text: 'Hi',
    }),
  ).rejects.toBeInstanceOf(MailProviderError)
})

it('returns MailResult on success', async () => {
  fetchMock.mockResolvedValue(
    new Response(JSON.stringify({ messageId: 'br-ok' }), { status: 201 }),
  )

  const adapter = makeBrevoAdapter({ apiKey: 'brevo-key', fetchImpl: fetchMock })
  const result = await adapter.send({
    from: 'from@example.com',
    to: 'to@example.com',
    subject: 'Subject',
    text: 'Hi',
  })

  expect(result).toEqual({ id: 'br-ok', provider: 'brevo' })
})
