import 'server-only'

import { createAdminClient } from '@/lib/supabase/admin'
import { markLeadUnsubscribed } from '@/lib/data/broker-lead-hooks'
import { sendEmail } from '@/lib/adapters/email'
import { SITE_URL, SUPPORT_EMAIL } from '@/lib/app-url'
import { emailPattern } from '@/lib/like'
import { DASHBOARD_LINKS, DEFAULT_TEMPLATES, renderTemplate, renderTemplateClean } from '@/lib/email-templates'
import {
  DEFAULT_PREFERENCES, preSendDecision, resolveTemplateMeta, type EmailPreferences, type EmailStream, type SendDecision, type TemplateMeta,
} from '@/lib/domain/email-policy'
import { createPreferenceToken, preferenceLinks } from '@/lib/email/tokens'

/**
 * The one central sender (2026-09-22). Every application email goes through
 * here: template (admin-managed copy) → stream and category → pre-send
 * checks (delivery suppression, hard bounce, marketing preferences, active
 * template) → render → unsubscribe footer for the updates stream → the right
 * Mail Agent → email_messages log with our client_reference.
 *
 * Tolerates migration 0028 not being applied: preferences read as defaults,
 * suppression as none, and the log insert is skipped — the email still goes.
 */

const missing = (e: { message?: string } | null | undefined) => !!e && /does not exist|schema cache|column/i.test(e.message ?? '')
export const normalizeEmail = (e: string) => e.trim().toLowerCase()
const isDemoAddress = (e: string) => /@(.+\.)?(users\.local|localhost|[^.]+\.(test|example|invalid))$/.test(e)

export interface SendResult {
  status: 'sent' | 'recorded_not_delivered' | 'suppressed' | 'skipped' | 'failed'
  reason?: string
  messageId?: string | null
  requestId?: string | null
  clientReference: string
  subject: string | null
  agent: string
  stream: EmailStream
}

interface Template { subject: string; body: string; active: boolean; version: number; footer: string; support: string; cta: string; meta: TemplateMeta }

async function loadTemplate(key: string): Promise<Template | null> {
  const admin = createAdminClient()
  const { data } = await admin.from('email_templates').select('subject, body, active, version, footer, support_contact, cta_text, email_stream, category_key, required').eq('key', key).maybeSingle()
  const d = DEFAULT_TEMPLATES.find((t) => t.key === key)
  if (data) {
    return { subject: data.subject, body: data.body, active: !!data.active, version: (data.version as number | null) ?? 1, footer: (data.footer as string | null) ?? '', support: (data.support_contact as string | null) ?? '', cta: (data.cta_text as string | null) ?? '', meta: resolveTemplateMeta(key, data as { email_stream?: string | null; category_key?: string | null; required?: boolean | null }) }
  }
  if (!d) return null
  return { subject: d.subject, body: d.body, active: true, version: 0, footer: '', support: '', cta: '', meta: resolveTemplateMeta(key) }
}

/** What we know about an address before sending: preferences, suppressions, delivery health, verified delivery address. */
export async function recipientContext(email: string, userId?: string | null) {
  const admin = createAdminClient()
  const norm = normalizeEmail(email)
  let uid = userId ?? null
  let sendTo = email.trim()
  if (!uid) {
    const { data: p } = await admin.from('profiles').select('id, delivery_email').ilike('email', emailPattern(norm)).maybeSingle()
    if (p) { uid = p.id; if (p.delivery_email) sendTo = p.delivery_email }
  } else {
    const { data: p } = await admin.from('profiles').select('delivery_email').eq('id', uid).maybeSingle()
    if (p?.delivery_email) sendTo = p.delivery_email
  }
  const sendNorm = normalizeEmail(sendTo)
  const [prefs, sups, state] = await Promise.all([
    uid ? admin.from('email_preferences').select('*').eq('user_id', uid).maybeSingle() : Promise.resolve({ data: null, error: null }),
    admin.from('email_suppressions').select('scope, campaign_type, expires_at, overridden_at').in('email_normalized', [norm, sendNorm]),
    admin.from('email_delivery_state').select('status').eq('email_normalized', sendNorm).maybeSingle(),
  ])
  const preferences: EmailPreferences | null = prefs.data ? { ...DEFAULT_PREFERENCES, ...(prefs.data as Partial<EmailPreferences>) } : uid ? DEFAULT_PREFERENCES : null
  return {
    userId: uid,
    sendTo,
    preferences,
    suppressions: missing(sups.error) ? [] : ((sups.data ?? []) as { scope: 'global' | 'marketing' | 'campaign_type'; campaign_type: string | null; expires_at: string | null; overridden_at: string | null }[]),
    delivery: missing(state.error) ? null : ((state.data ?? null) as { status: 'ok' | 'soft_bouncing' | 'hard_bounced' } | null),
  }
}

export async function sendPlatformEmail(params: {
  templateKey: string
  to: string
  data: Record<string, string>
  userId?: string | null
  campaignId?: string | null
  campaignType?: string | null
  actorUserId?: string | null
  /** Drop lines with missing variables (default true). */
  clean?: boolean
  /** Extra provider tags. */
  tags?: Record<string, string>
  /** Public origin for links when not the canonical site. */
  origin?: string
  /** Copies — kept out of suppression checks; the primary recipient decides. */
  cc?: string[]
  /** Files to attach (base64). */
  attachments?: Array<{ name: string; mimeType: string; contentBase64: string }>
  /** Required operational details appended even when a saved template is customized. */
  appendText?: string
  /** Mark a deliberate test send without changing the saved template. */
  subjectPrefix?: string
}): Promise<SendResult> {
  const admin = createAdminClient()
  const clientReference = `hha_${crypto.randomUUID().replace(/-/g, '')}`
  const template = await loadTemplate(params.templateKey)
  const stream: EmailStream = template?.meta.stream ?? 'transactional'
  const base: Omit<SendResult, 'status'> = { clientReference, subject: null, agent: 'none', stream }
  const log = async (row: Record<string, unknown>) => {
    const { error } = await admin.from('email_messages').insert({
      client_reference: clientReference, recipient_user_id: params.userId ?? null, recipient_email: params.to, email_normalized: normalizeEmail(params.to),
      email_stream: stream, template_key: params.templateKey, template_version: template?.version ?? null, category_key: template?.meta.category ?? null,
      campaign_id: params.campaignId ?? null, campaign_type: params.campaignType ?? null, actor_user_id: params.actorUserId ?? null, ...row,
    })
    if (error && !missing(error)) console.error('email_messages insert failed', error.message)
  }
  if (!template) { await log({ status: 'skipped', error: 'template missing' }); return { ...base, status: 'skipped', reason: 'template_missing' } }

  const ctx = await recipientContext(params.to, params.userId)
  const decision: SendDecision = preSendDecision({ meta: template.meta, templateActive: template.active, preferences: ctx.preferences, suppressions: ctx.suppressions, delivery: ctx.delivery, campaignType: params.campaignType })
  if (!decision.allowed) {
    await log({ status: 'suppressed', suppressed_reason: decision.reason, recipient_user_id: ctx.userId })
    return { ...base, status: 'suppressed', reason: decision.reason }
  }

  const token = await createPreferenceToken({ email: ctx.sendTo, userId: ctx.userId })
  const links = preferenceLinks(token, params.origin ?? SITE_URL)
  const data: Record<string, string> = {
    support_email: template.support || SUPPORT_EMAIL, company_footer: template.footer, ...DASHBOARD_LINKS,
    unsubscribe_link: links.unsubscribe, preferences_link: links.preferences, ...params.data,
  }
  const render = (t: string) => (params.clean === false ? renderTemplate(t, data) : renderTemplateClean(t, data))
  const subject = `${params.subjectPrefix ?? ''}${render(template.subject)}`
  let text = render(template.body)
  if (params.appendText) text += `\n\n${params.appendText}`
  if (stream === 'updates') {
    // §8: every updates email carries the unsubscribe and preference links, whatever the template says.
    text += `\n\n—\nYou receive this because you have a HeavyHaul Agent relationship or asked about our services.\nUnsubscribe from updates: ${links.unsubscribe}\nManage email preferences: ${links.preferences}\nHeavyHaul Agent · ${SUPPORT_EMAIL}`
  }

  if (isDemoAddress(ctx.sendTo)) {
    await log({ status: 'recorded_not_delivered', subject, error: 'demo address', recipient_user_id: ctx.userId, detail: { ...(params.cc?.length ? { cc: params.cc } : {}), ...(params.attachments?.length ? { attachments: params.attachments.map((a) => a.name) } : {}) } })
    return { ...base, status: 'recorded_not_delivered', reason: 'demo_address', subject, messageId: null, requestId: null }
  }
  const r = await sendEmail({ to: ctx.sendTo, subject, text, stream, clientReference, tags: { template: params.templateKey, stream, ...(params.tags ?? {}) }, unsubscribeUrl: stream === 'updates' ? links.unsubscribe : undefined, cc: params.cc, attachments: params.attachments })
  await log({
    status: r.status, subject, agent: r.agent, zepto_request_id: r.request_id, sent_at: r.status === 'sent' ? new Date().toISOString() : null,
    error: r.status === 'failed' ? r.error : null, recipient_user_id: ctx.userId, detail: { message_id: r.message_id, send_to: ctx.sendTo, ...(params.cc?.length ? { cc: params.cc } : {}), ...(params.attachments?.length ? { attachments: params.attachments.map((a) => a.name) } : {}) },
  })
  return { ...base, status: r.status, agent: r.agent, subject, messageId: r.message_id, requestId: r.request_id, reason: r.status === 'failed' ? r.error : undefined }
}

/* ---------------- preferences ---------------- */

export async function loadPreferences(userId: string): Promise<{ available: boolean; prefs: EmailPreferences }> {
  const { data, error } = await createAdminClient().from('email_preferences').select('*').eq('user_id', userId).maybeSingle()
  if (missing(error)) return { available: false, prefs: DEFAULT_PREFERENCES }
  return { available: true, prefs: { ...DEFAULT_PREFERENCES, ...((data ?? {}) as Partial<EmailPreferences>) } }
}

export async function savePreferences(userId: string, patch: Partial<EmailPreferences>, actorLabel: string) {
  // Required categories can never be turned off (§7).
  const clean = { ...patch, account_security: true }
  const { error } = await createAdminClient().from('email_preferences').upsert({ user_id: userId, ...clean, updated_by: actorLabel, updated_at: new Date().toISOString() }, { onConflict: 'user_id' })
  if (error) return { ok: false as const, error: missing(error) ? 'Email preferences need database migration 0028.' : error.message }
  return { ok: true as const }
}

/** Unsubscribe from the updates stream: a known user gets every updates category turned off; an unknown address gets a marketing suppression. */
export async function unsubscribeUpdates(t: { email: string; userId: string | null }, source: string) {
  const admin = createAdminClient()
  if (t.userId) {
    const r = await savePreferences(t.userId, { product_updates: false, newsletter: false, marketing_campaigns: false, pilot_opportunities: false, broker_opportunities: false, carrier_opportunities: false }, source)
    if (!r.ok) return r
  }
  const { error } = await admin.from('email_suppressions').upsert(
    { email_normalized: normalizeEmail(t.email), scope: 'marketing', campaign_type: null, reason: 'user_unsubscribe', source },
    { onConflict: 'email_normalized,scope,campaign_type', ignoreDuplicates: true },
  )
  if (error && !missing(error) && !/duplicate|unique/i.test(error.message)) return { ok: false as const, error: error.message }
  await markLeadUnsubscribed(t.email, source)
  // Keep the pilot pipeline's own list in step (§23 of the pilot spec).
  await admin.from('pilot_suppressions').upsert({ email: normalizeEmail(t.email), reason: 'unsubscribed', note: source, created_by: 'preference center' }, { onConflict: 'email', ignoreDuplicates: true })
  return { ok: true as const }
}

/** Re-enable updates for a known user (preference center "turn back on"). Removes the user_unsubscribe marketing suppression only. */
export async function resubscribeUpdates(t: { email: string; userId: string | null }, patch: Partial<EmailPreferences>, source: string) {
  const admin = createAdminClient()
  if (t.userId) { const r = await savePreferences(t.userId, patch, source); if (!r.ok) return r }
  await admin.from('email_suppressions').update({ overridden_at: new Date().toISOString(), manually_overridden_by: source }).eq('email_normalized', normalizeEmail(t.email)).eq('scope', 'marketing').eq('reason', 'user_unsubscribe').is('overridden_at', null)
  return { ok: true as const }
}
