/**
 * Resend email client wrapper.
 *
 * All email sends go through sendEmail(). Never construct a Resend client
 * outside this module - secrets must not be spread across the codebase.
 */

import { createMail } from '@platform-modules/mail';
import { makeResendAdapter } from '@platform-modules/mail/resend';
import { renderToStaticMarkup } from 'react-dom/server';
import type { ReactElement } from 'react';

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

export interface SendEmailOptions {
  /** Recipient email address. Never log this value - it is PII. */
  to: string;
  subject: string;
  /** Fully rendered React Email component (pass the JSX element). */
  react: ReactElement;
  /** Optional Resend tags for analytics / filtering. */
  tags?: Array<{ name: string; value: string }>;
}

export interface SendEmailResult {
  success: boolean;
  messageId?: string;
  error?: string;
}

/** Minimal env shape required by this module. */
export interface ResendEnv {
  RESEND_API_KEY: string;
  RESEND_FROM_EMAIL: string;
  /** Set to 'production' in prod — any other value enables mock capture. */
  ENVIRONMENT?: string;
  /** CF D1 binding for dev email capture. Present only in non-prod workers. */
  EMAIL_MOCK_DB?: D1Database;
}

// ─── Render helper ────────────────────────────────────────────────────────────

/**
 * Renders a React Email component to an HTML string.
 * Used internally and exposed for callers that need the raw HTML.
 */
export function renderEmail(component: ReactElement): string {
  return '<!DOCTYPE html>' + renderToStaticMarkup(component);
}

// ─── Send helper ─────────────────────────────────────────────────────────────

/**
 * Sends a transactional email via Resend.
 *
 * Errors are caught and returned rather than thrown so that a failed email
 * does not crash a purchase flow - the caller decides whether to retry.
 */
export async function sendEmail(
  env: ResendEnv,
  options: SendEmailOptions,
): Promise<SendEmailResult> {
  if (env.ENVIRONMENT && env.ENVIRONMENT !== 'production') {
    const { captureFactoryMail } = await import('@/server/testing/factory/mail-capture');
    const html = renderEmail(options.react);
    if (captureFactoryMail(options.to, options.subject, html)) {
      return { success: true, messageId: `factory-${crypto.randomUUID()}` };
    }
  }

  // Dev mock — capture to D1 instead of sending to Resend.
  if (env.ENVIRONMENT && env.ENVIRONMENT !== 'production' && env.EMAIL_MOCK_DB) {
    try {
      const html = renderEmail(options.react);
      // D1 `.exec()` splits its input on newlines and runs each line as a
      // standalone statement, so a multi-line DDL string fails with
      // "incomplete input". Use `.prepare().run()` (same API as the INSERT
      // below) which executes one complete statement regardless of newlines.
      await env.EMAIL_MOCK_DB.prepare(
        `CREATE TABLE IF NOT EXISTS mock_emails (
          id TEXT PRIMARY KEY,
          created_at TEXT NOT NULL,
          from_addr TEXT NOT NULL,
          to_addr TEXT NOT NULL,
          subject TEXT NOT NULL,
          html TEXT NOT NULL,
          tags TEXT NOT NULL
        )`,
      ).run();
      const id = crypto.randomUUID();
      await env.EMAIL_MOCK_DB.prepare(
        `INSERT INTO mock_emails (id, created_at, from_addr, to_addr, subject, html, tags) VALUES (?, ?, ?, ?, ?, ?, ?)`,
      )
        .bind(
          id,
          new Date().toISOString(),
          env.RESEND_FROM_EMAIL ?? '',
          options.to,
          options.subject,
          html,
          JSON.stringify(options.tags ?? []),
        )
        .run();
      return { success: true, messageId: `mock-${id}` };
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'mock write failed';
      console.error('[email-mock] D1 write error', msg);
      return { success: false, error: msg };
    }
  }

  // Factory preview uses a placeholder Resend key; never call the live API.
  if (env.RESEND_API_KEY.startsWith('re_factory')) {
    return { success: true, messageId: `factory-noop-${crypto.randomUUID()}` };
  }

  if (!env.RESEND_API_KEY) {
    console.error('[resend] RESEND_API_KEY not configured');
    return { success: false, error: 'RESEND_API_KEY not configured' };
  }
  if (!env.RESEND_FROM_EMAIL) {
    console.error('[resend] RESEND_FROM_EMAIL not configured');
    return { success: false, error: 'RESEND_FROM_EMAIL not configured' };
  }

  try {
    const html = renderEmail(options.react);
    const tags = options.tags?.reduce<Record<string, string>>((acc, tag) => {
      acc[tag.name] = tag.value;
      return acc;
    }, {});
    const mail = createMail(makeResendAdapter({ apiKey: env.RESEND_API_KEY }));
    const result = await mail.send({
      from: env.RESEND_FROM_EMAIL,
      to: options.to,
      subject: options.subject,
      html,
      tags,
    });
    return { success: true, messageId: result.id };
  } catch (err) {
    const message = err instanceof Error ? err.message : 'Unknown send error';
    console.error('[resend] throw', { message });
    return { success: false, error: message };
  }
}
