import {
  MailProviderError,
  type MailAdapter,
  type MailMessage,
  type MailResult,
} from './index.js'

export type BrevoAdapterConfig = {
  apiKey: string
  fetchImpl?: typeof fetch
}

const BREVO_URL = 'https://api.brevo.com/v3/smtp/email'

function toRecipients(value: string | string[]): { email: string }[] {
  const list = Array.isArray(value) ? value : [value]
  return list.map((email) => ({ email }))
}

function parseFrom(from: string): { email: string; name?: string } {
  const angle = from.match(/^(.+?)\s*<([^>]+)>$/)
  if (angle) {
    return { name: angle[1]!.trim(), email: angle[2]!.trim() }
  }
  return { email: from.trim() }
}

export function makeBrevoAdapter({
  apiKey,
  fetchImpl = fetch,
}: BrevoAdapterConfig): MailAdapter {
  return {
    async send(msg: MailMessage): Promise<MailResult> {
      const body = {
        sender: parseFrom(msg.from),
        to: toRecipients(msg.to),
        cc: msg.cc ? toRecipients(msg.cc) : undefined,
        bcc: msg.bcc ? toRecipients(msg.bcc) : undefined,
        replyTo: msg.replyTo ? { email: msg.replyTo } : undefined,
        subject: msg.subject,
        htmlContent: msg.html,
        textContent: msg.text,
        headers: msg.headers,
      }

      let response: Response
      try {
        response = await fetchImpl(BREVO_URL, {
          method: 'POST',
          headers: {
            'api-key': apiKey,
            'content-type': 'application/json',
            accept: 'application/json',
            // Brevo native idempotency (UUID, 30-min TTL — verified 2026-06-14).
            // Forwarded as-is; a malformed/reused key surfaces as the provider's
            // error which the adapter maps to MailProviderError below.
            ...(msg.idempotencyKey ? { 'Idempotency-Key': msg.idempotencyKey } : {}),
          },
          body: JSON.stringify(body),
        })
      } catch (err) {
        throw new MailProviderError(
          err instanceof Error ? err.message : 'brevo fetch failed',
          'brevo',
          true,
          err,
        )
      }

      const payload = (await response.json().catch(() => null)) as
        | { messageId?: string; message?: string }
        | null

      if (!response.ok) {
        throw new MailProviderError(
          payload?.message ?? `brevo request failed (${response.status})`,
          'brevo',
          response.status >= 500,
          payload,
        )
      }

      if (!payload?.messageId) {
        throw new MailProviderError('brevo returned no message id', 'brevo', false, payload)
      }

      return { id: payload.messageId, provider: 'brevo' }
    },
  }
}
