/**
 * Support notification dispatcher — ticket events only (phase 3).
 *
 * Inserts outbox rows (kind = support.notif.email / support.notif.push)
 * within an existing Drizzle transaction so the notifications are atomically
 * coupled to the workflow write. After the tx commits, call enqueueOutbox()
 * for each inserted id.
 *
 * Recipient matrix (tickets, phase 3):
 *   ticket_opened      → customer email + push
 *   ticket_resolved    → customer email + push
 *   ticket_reopened    → site email only (support_notification_emails config, fallback RESEND_FROM_EMAIL)
 *   escalated_to_human → customer email + site email
 *
 */

import type { DrizzleClient } from '@/server/db/client.js';
import { insertOutboxRow } from '@/server/db/queries/outbox.js';

// ─── Types ─────────────────────────────────────────────────────────────────────

export type SupportNotifEvent =
  | 'ticket_opened'
  | 'ticket_resolved'
  | 'ticket_reopened'
  | 'escalated_to_human';

export interface SupportNotifContext {
  ticketId: string;
  openerId: string;
  openerLocale: 'he' | 'en';
  subject: string;
  category: string;
  ticketUrl: string;
  reason?: string;
  resolution?: string;
  /** Customer email address (decrypted, ready to send). May be undefined for push-only. */
  customerEmail?: string;
  /** Site notification emails from system_config, or fallback RESEND_FROM_EMAIL. */
  siteEmails?: string[];
}

export interface EnqueuedRow {
  id: string;
}

/** Injected inserter for testability. Real usage: wrap in transaction. */
export type OutboxInserter = (
  db: DrizzleClient,
  rows: Array<{ aggregateType: string; aggregateId: string; eventType: string; payload: unknown }>,
) => Promise<string[]>;

async function defaultInserter(
  db: DrizzleClient,
  rows: Array<{ aggregateType: string; aggregateId: string; eventType: string; payload: unknown }>,
): Promise<string[]> {
  if (rows.length === 0) return [];
  const inserted: string[] = [];
  for (const row of rows) {
    const out = await insertOutboxRow(db, row);
    inserted.push(out.id);
  }
  return inserted;
}

// ─── Main ──────────────────────────────────────────────────────────────────────

/**
 * Enqueue notification rows for a support ticket event.
 *
 * Must be called within a Drizzle transaction that also writes the primary
 * ticket row, so notifications are coupled atomically.
 *
 * @returns Array of outbox row IDs to pass to enqueueOutbox() after commit.
 */
export async function enqueueSupportNotification(
  db: DrizzleClient,
  event: SupportNotifEvent,
  ctx: SupportNotifContext,
  _inserter: OutboxInserter = defaultInserter,
): Promise<string[]> {
  const rows: Array<{
    aggregateType: string;
    aggregateId: string;
    eventType: string;
    payload: unknown;
  }> = [];

  switch (event) {
    case 'ticket_opened': {
      // Customer email
      if (ctx.customerEmail) {
        rows.push({
          aggregateType: 'support_ticket',
          aggregateId: ctx.ticketId,
          eventType: 'support.notif.email',
          payload: {
            to: ctx.customerEmail,
            templateKey: 'support.ticket_opened',
            params: {
              ticketId: ctx.ticketId,
              subject: ctx.subject,
              category: ctx.category,
              ticketUrl: ctx.ticketUrl,
            },
            locale: ctx.openerLocale,
          },
        });
      }
      // Customer push
      rows.push({
        aggregateType: 'support_ticket',
        aggregateId: ctx.ticketId,
        eventType: 'support.notif.push',
        payload: {
          userId: ctx.openerId,
          templateKey: 'support.ticket_opened',
          params: {
            ticketId: ctx.ticketId,
            subject: ctx.subject,
            ticketUrl: ctx.ticketUrl,
          },
          locale: ctx.openerLocale,
        },
      });
      break;
    }

    case 'ticket_resolved': {
      // Customer email
      if (ctx.customerEmail) {
        rows.push({
          aggregateType: 'support_ticket',
          aggregateId: ctx.ticketId,
          eventType: 'support.notif.email',
          payload: {
            to: ctx.customerEmail,
            templateKey: 'support.ticket_resolved',
            params: {
              ticketId: ctx.ticketId,
              resolution: ctx.resolution ?? '',
              ticketUrl: ctx.ticketUrl,
              reopenUrl: ctx.ticketUrl + '/reopen',
            },
            locale: ctx.openerLocale,
          },
        });
      }
      // Customer push
      rows.push({
        aggregateType: 'support_ticket',
        aggregateId: ctx.ticketId,
        eventType: 'support.notif.push',
        payload: {
          userId: ctx.openerId,
          templateKey: 'support.ticket_resolved',
          params: {
            ticketId: ctx.ticketId,
            resolution: ctx.resolution ?? '',
            ticketUrl: ctx.ticketUrl,
          },
          locale: ctx.openerLocale,
        },
      });
      break;
    }

    case 'ticket_reopened': {
      // Site emails only — no PII, ID + category only
      const targets = ctx.siteEmails && ctx.siteEmails.length > 0 ? ctx.siteEmails : [];
      for (const to of targets) {
        rows.push({
          aggregateType: 'support_ticket',
          aggregateId: ctx.ticketId,
          eventType: 'support.notif.email',
          payload: {
            to,
            templateKey: 'support.ticket_reopened',
            params: {
              ticketId: ctx.ticketId,
              ticketUrl: ctx.ticketUrl,
            },
            locale: 'he' as const,
          },
        });
      }
      break;
    }

    case 'escalated_to_human': {
      // Customer email
      if (ctx.customerEmail) {
        rows.push({
          aggregateType: 'support_ticket',
          aggregateId: ctx.ticketId,
          eventType: 'support.notif.email',
          payload: {
            to: ctx.customerEmail,
            templateKey: 'support.escalated_to_human',
            params: {
              ticketId: ctx.ticketId,
              reason: ctx.reason ?? '',
              ticketUrl: ctx.ticketUrl,
            },
            locale: ctx.openerLocale,
          },
        });
      }
      // Site emails
      const siteTargets = ctx.siteEmails && ctx.siteEmails.length > 0 ? ctx.siteEmails : [];
      for (const to of siteTargets) {
        rows.push({
          aggregateType: 'support_ticket',
          aggregateId: ctx.ticketId,
          eventType: 'support.notif.email',
          payload: {
            to,
            templateKey: 'support.escalated_to_human',
            params: {
              ticketId: ctx.ticketId,
              reason: ctx.reason ?? '',
              ticketUrl: ctx.ticketUrl,
            },
            locale: 'he' as const,
          },
        });
      }
      break;
    }
  }

  return _inserter(db, rows);
}
