import 'server-only'

import { createAdminClient } from '@/lib/supabase/admin'

/**
 * Freight Broker Leads — the small hooks other modules call (2026-09-23):
 * the webhook processor (delivered / opened / clicked / bounced /
 * complained), the preference centre (unsubscribed), the join page (signed
 * up) and the broker company flow (relation confirmed or declined).
 *
 * Deliberately imports nothing from the email sender so it can be used from
 * there without a cycle. Every call tolerates migration 0030 not being
 * applied — a lead-management column that does not exist is simply not
 * written — and never throws into the caller's flow.
 */

type Admin = ReturnType<typeof createAdminClient>
const missing = (e: { message?: string } | null | undefined) => !!e && /does not exist|schema cache|column/i.test(e.message ?? '')

export type LeadEventType =
  | 'imported' | 'edited' | 'note' | 'tagged' | 'untagged' | 'suppressed' | 'unsuppressed' | 'review_resolved'
  | 'enrolled' | 'email_sent' | 'email_skipped' | 'email_failed' | 'delivered' | 'opened' | 'clicked' | 'bounced' | 'complained' | 'unsubscribed'
  | 'join_link_opened' | 'signed_up' | 'confirmed' | 'declined' | 'stopped'

export async function logLeadEvent(params: {
  leadId: string
  type: LeadEventType
  campaignId?: string | null
  messageId?: string | null
  templateKey?: string | null
  step?: number | null
  actorLabel?: string | null
  detail?: Record<string, unknown> | null
  at?: string
}, admin: Admin = createAdminClient()): Promise<void> {
  const { error } = await admin.from('broker_lead_events').insert({
    lead_id: params.leadId, event_type: params.type, campaign_id: params.campaignId ?? null, message_id: params.messageId ?? null,
    template_key: params.templateKey ?? null, step: params.step ?? null, actor_label: params.actorLabel ?? null, detail: params.detail ?? null,
    ...(params.at ? { created_at: params.at } : {}),
  })
  if (error && !missing(error)) console.error('broker_lead_events insert failed', error.message)
}

async function leadByEmail(email: string, admin: Admin): Promise<{ id: string; invitation_status: string } | null> {
  const { data, error } = await admin.from('broker_agent_leads').select('id, invitation_status').eq('email_normalized', email.trim().toLowerCase()).order('created_at', { ascending: false }).limit(1).maybeSingle()
  if (error) return null
  return (data as { id: string; invitation_status: string } | null) ?? null
}

async function leadById(id: string, admin: Admin): Promise<{ id: string; invitation_status: string } | null> {
  const { data } = await admin.from('broker_agent_leads').select('id, invitation_status').eq('id', id).maybeSingle()
  return (data as { id: string; invitation_status: string } | null) ?? null
}

/** A ZeptoMail delivery event landed for this address. Updates the lead's last-activity columns and its timeline. */
export async function recordLeadEmailEvent(params: {
  email: string
  type: 'delivered' | 'opened' | 'clicked' | 'soft_bounce' | 'hard_bounce' | 'spam_complaint'
  messageId?: string | null
  campaignId?: string | null
  at: string
  reason?: string | null
}): Promise<void> {
  try {
    const admin = createAdminClient()
    const lead = await leadByEmail(params.email, admin)
    if (!lead) return
    const patch: Record<string, unknown> = { updated_at: params.at }
    let type: LeadEventType | null = null
    if (params.type === 'delivered') { patch.last_delivered_at = params.at; type = 'delivered' }
    if (params.type === 'opened') { patch.last_opened_at = params.at; type = 'opened' }
    if (params.type === 'clicked') { patch.last_clicked_at = params.at; type = 'clicked' }
    if (params.type === 'hard_bounce') { patch.bounced_at = params.at; type = 'bounced' }
    if (params.type === 'soft_bounce') { type = 'bounced' }
    if (params.type === 'spam_complaint') { patch.suppressed_at = params.at; patch.suppressed_reason = 'spam_complaint'; patch.suppressed_by = 'zeptomail webhook'; type = 'complained' }
    if (!type) return
    const { error } = await admin.from('broker_agent_leads').update(patch).eq('id', lead.id)
    if (error && !missing(error)) console.error('lead event update failed', error.message)
    await logLeadEvent({ leadId: lead.id, type, campaignId: params.campaignId, messageId: params.messageId, at: params.at, detail: { kind: params.type, reason: params.reason ?? null } }, admin)
  } catch (e) {
    console.error('recordLeadEmailEvent', e)
  }
}

/** The address unsubscribed from updates (preference centre or one-click link). */
export async function markLeadUnsubscribed(email: string, source: string): Promise<void> {
  try {
    const admin = createAdminClient()
    const lead = await leadByEmail(email, admin)
    if (!lead) return
    const now = new Date().toISOString()
    const { error } = await admin.from('broker_agent_leads').update({ unsubscribed_at: now, invitation_status: 'opted_out', updated_at: now }).eq('id', lead.id)
    if (error && missing(error)) await admin.from('broker_agent_leads').update({ invitation_status: 'opted_out', updated_at: now }).eq('id', lead.id)
    await logLeadEvent({ leadId: lead.id, type: 'unsubscribed', actorLabel: source, at: now }, admin)
  } catch (e) {
    console.error('markLeadUnsubscribed', e)
  }
}

/** The lead created an account through their join link (or any email-code sign-in with that address). */
export async function markLeadSignedUp(params: { leadId?: string | null; email: string; userId: string; via: string }): Promise<void> {
  try {
    const admin = createAdminClient()
    const lead = params.leadId ? await leadById(params.leadId, admin) : await leadByEmail(params.email, admin)
    if (!lead) return
    const now = new Date().toISOString()
    const { data: cur } = await admin.from('broker_agent_leads').select('signed_up_at').eq('id', lead.id).maybeSingle()
    if ((cur as { signed_up_at?: string | null } | null)?.signed_up_at) return // already recorded
    const { error } = await admin.from('broker_agent_leads').update({ signed_up_at: now, signed_up_user_id: params.userId, updated_at: now }).eq('id', lead.id)
    if (error && !missing(error)) console.error('markLeadSignedUp', error.message)
    await logLeadEvent({ leadId: lead.id, type: 'signed_up', at: now, detail: { via: params.via, user_id: params.userId } }, admin)
    // campaigns that emailed this lead get a sign-up
    const { data: recs } = await admin.from('email_campaign_recipients').select('campaign_id, sends').eq('lead_id', lead.id).gt('sends', 0)
    for (const r of (recs ?? []) as Array<{ campaign_id: string; sends: number }>) {
      const { data: c } = await admin.from('email_campaigns').select('signed_up_count').eq('id', r.campaign_id).maybeSingle()
      if (c) await admin.from('email_campaigns').update({ signed_up_count: ((c as { signed_up_count?: number }).signed_up_count ?? 0) + 1, updated_at: now }).eq('id', r.campaign_id)
    }
  } catch (e) {
    console.error('markLeadSignedUp', e)
  }
}

/** The lead answered the "do you still represent this brokerage?" question. `yes` is the conversion. */
export async function markLeadDecision(params: { leadId: string; userId: string; decision: 'confirmed' | 'declined'; actorLabel: string }): Promise<void> {
  try {
    const admin = createAdminClient()
    const now = new Date().toISOString()
    await logLeadEvent({ leadId: params.leadId, type: params.decision, at: now, actorLabel: params.actorLabel, detail: { user_id: params.userId } }, admin)
    const { data: recs } = await admin.from('email_campaign_recipients').select('id, campaign_id, sends, status').eq('lead_id', params.leadId)
    for (const r of (recs ?? []) as Array<{ id: string; campaign_id: string; sends: number; status: string }>) {
      if (params.decision === 'confirmed' && r.sends > 0) {
        await admin.from('email_campaign_recipients').update({ status: 'converted', converted_at: now, updated_at: now }).eq('id', r.id)
        const { data: c } = await admin.from('email_campaigns').select('conversion_count').eq('id', r.campaign_id).maybeSingle()
        if (c) await admin.from('email_campaigns').update({ conversion_count: ((c as { conversion_count?: number }).conversion_count ?? 0) + 1, updated_at: now }).eq('id', r.campaign_id)
      } else if (r.status === 'pending' || r.status === 'scheduled') {
        await admin.from('email_campaign_recipients').update({ status: 'stopped', stop_reason: params.decision === 'confirmed' ? 'already_converted' : 'declined', updated_at: now }).eq('id', r.id)
      }
    }
  } catch (e) {
    console.error('markLeadDecision', e)
  }
}
