import 'server-only'

import { SUPPORT_EMAIL } from '@/lib/app-url'
import { STREAM_SENDERS, type EmailStream } from '@/lib/domain/email-policy'

/**
 * Outbound email seam — two ZeptoMail Mail Agents (2026-09-22).
 *
 *   transactional  HHA Transactional  info@heavyhaulagent.com     ZEPTOMAIL_TRANSACTIONAL_TOKEN
 *   updates        HHA Updates        updates@heavyhaulagent.com  ZEPTOMAIL_UPDATES_TOKEN
 *
 * Separate agents = separate keys, suppression lists, reporting and webhooks,
 * so a bad campaign can never sit in the same lane as password resets.
 * Compatibility: with only the original ZEPTOMAIL_SEND_TOKEN / EMAIL_FROM
 * set, both streams fall back to that one agent (the 2026-09-15 setup).
 *
 *   EMAIL_PROVIDER unset → `recorded`: nothing leaves the server; the caller
 *   logs the message as recorded_not_delivered and the UI says so.
 *
 * Every message carries our `client_reference` so ZeptoMail webhooks map
 * straight back to email_messages. No secret ever lives in code.
 */

export interface OutboundEmail {
  to: string
  subject: string
  text: string
  /** Which Mail Agent sends it. */
  stream: EmailStream
  /** Our email_messages.client_reference (e.g. hha_9f3c…). */
  clientReference?: string
  /** Free-form tags for the provider (campaign id, template key, kind). */
  tags?: Record<string, string>
  /** Updates stream: List-Unsubscribe header target. */
  unsubscribeUrl?: string
  /** Copies (transactional only in practice — e.g. the requester of a permit order). */
  cc?: string[]
  /** Files (base64). Keep each under 8 MB and the email under 15 MB. */
  attachments?: Array<{ name: string; mimeType: string; contentBase64: string }>
}

export type EmailSendResult =
  | { status: 'recorded_not_delivered'; provider: 'none'; message_id: null; request_id: null; agent: string }
  | { status: 'sent'; provider: 'zeptomail'; message_id: string | null; request_id: string | null; agent: string }
  | { status: 'failed'; provider: 'zeptomail'; message_id: null; request_id: null; agent: string; error: string }

interface AgentConfig { token: string; from: string; fromName: string; replyTo: string; agent: string }

/** Env for a stream, with the single-agent fallback. Null when nothing is configured. */
export function agentConfig(stream: EmailStream): AgentConfig | null {
  if (process.env.EMAIL_PROVIDER !== 'zeptomail') return null
  const shared = process.env.ZEPTOMAIL_SEND_TOKEN?.trim()
  const token = (stream === 'updates' ? process.env.ZEPTOMAIL_UPDATES_TOKEN : process.env.ZEPTOMAIL_TRANSACTIONAL_TOKEN)?.trim() || shared
  const from = (stream === 'updates' ? process.env.EMAIL_FROM_UPDATES : process.env.EMAIL_FROM_TRANSACTIONAL)?.trim() || process.env.EMAIL_FROM?.trim()
  if (!token || !from) return null
  const dedicated = stream === 'updates' ? !!process.env.ZEPTOMAIL_UPDATES_TOKEN : !!process.env.ZEPTOMAIL_TRANSACTIONAL_TOKEN
  return {
    token: token.replace(/^Zoho-enczapikey\s+/i, ''),
    from,
    fromName: (stream === 'updates' ? process.env.EMAIL_FROM_NAME_UPDATES : process.env.EMAIL_FROM_NAME)?.trim() || STREAM_SENDERS[stream].name,
    replyTo: process.env.EMAIL_REPLY_TO?.trim() || SUPPORT_EMAIL,
    agent: dedicated ? STREAM_SENDERS[stream].agent : 'shared',
  }
}

export function emailDeliveryConfigured(stream: EmailStream = 'transactional'): boolean {
  return agentConfig(stream) !== null
}

export async function sendEmail(email: OutboundEmail): Promise<EmailSendResult> {
  const cfg = agentConfig(email.stream)
  if (!cfg) return { status: 'recorded_not_delivered', provider: 'none', message_id: null, request_id: null, agent: 'none' }
  return sendViaZeptoMail(email, cfg)
}

const ZEPTOMAIL_URL = 'https://api.zeptomail.com/v1.1/email'

async function sendViaZeptoMail(email: OutboundEmail, cfg: AgentConfig): Promise<EmailSendResult> {
  const body: Record<string, unknown> = {
    from: { address: cfg.from, name: cfg.fromName },
    to: [{ email_address: { address: email.to } }],
    ...(email.cc?.length ? { cc: email.cc.map((address) => ({ email_address: { address } })) } : {}),
    ...(email.attachments?.length ? { attachments: email.attachments.map((a) => ({ name: a.name, mime_type: a.mimeType, content: a.contentBase64 })) } : {}),
    reply_to: [{ address: cfg.replyTo, name: cfg.fromName }],
    subject: email.subject,
    textbody: email.text,
    htmlbody: textToHtml(email.text),
    track_clicks: email.stream === 'updates',
    track_opens: email.stream === 'updates',
    ...(email.clientReference ? { client_reference: email.clientReference } : {}),
    ...(email.unsubscribeUrl ? { mime_headers: { 'List-Unsubscribe': `<${email.unsubscribeUrl}>`, 'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click' } } : {}),
  }
  try {
    const res = await fetch(ZEPTOMAIL_URL, {
      method: 'POST',
      headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Zoho-enczapikey ${cfg.token}` },
      body: JSON.stringify(body),
      signal: AbortSignal.timeout(15_000),
    })
    const json = (await res.json().catch(() => ({}))) as { data?: Array<{ message_id?: string; additional_info?: Array<{ message_id?: string }> }>; request_id?: string; message?: string; error?: { message?: string; details?: Array<{ message?: string }> } }
    if (!res.ok) {
      const detail = json.error?.details?.[0]?.message || json.error?.message || json.message || `HTTP ${res.status}`
      return { status: 'failed', provider: 'zeptomail', message_id: null, request_id: null, agent: cfg.agent, error: detail }
    }
    const messageId = json.data?.[0]?.message_id ?? json.data?.[0]?.additional_info?.[0]?.message_id ?? null
    return { status: 'sent', provider: 'zeptomail', message_id: messageId, request_id: json.request_id ?? null, agent: cfg.agent }
  } catch (e) {
    return { status: 'failed', provider: 'zeptomail', message_id: null, request_id: null, agent: cfg.agent, error: e instanceof Error ? e.message : 'Network error' }
  }
}

/** Plain-text templates → minimal HTML: escaped, paragraphs on blank lines, links clickable. */
export function textToHtml(text: string): string {
  const esc = (s: string) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
  const linkify = (s: string) => s.replace(/(https?:\/\/[^\s<]+)/g, (u) => `<a href="${u}">${u}</a>`)
  const paragraphs = text.split(/\n{2,}/).map((p) => `<p>${linkify(esc(p)).replace(/\n/g, '<br>')}</p>`)
  return `<div style="font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:1.5;color:#1f2937">${paragraphs.join('')}</div>`
}
