import { renderTemplate } from './renderer.js';
import { sendEmail } from './channels/email.js';
import * as repo from './repository.js';
import type { DeliveryLogDoc, EmailChannelConfig } from './types.js';

// ── Delivery Dispatcher ──────────────────────────────────────
// Routes delivery requests to the correct channel adapter.
// Logs all deliveries to Cosmos for audit and debugging.

/**
 * Resolve email config from environment. Defaults to console provider for dev.
 */
export function resolveEmailConfig(): EmailChannelConfig {
  const provider = (process.env.EMAIL_PROVIDER || 'console') as EmailChannelConfig['provider'];
  return {
    provider,
    apiKey: process.env.EMAIL_API_KEY,
    fromEmail: process.env.EMAIL_FROM_ADDRESS || 'noreply@bytelyst.com',
    fromName: process.env.EMAIL_FROM_NAME || 'ByteLyst',
  };
}

/**
 * Send a templated email. Renders the template, sends via configured channel,
 * and logs the delivery attempt.
 */
export async function dispatchEmail(
  options: {
    to: string;
    templateId: string;
    variables: Record<string, string>;
    productId: string;
    userId?: string;
  },
  log: { info: (...a: unknown[]) => void; error: (...a: unknown[]) => void }
): Promise<{ success: boolean; messageId?: string; error?: string }> {
  const config = resolveEmailConfig();
  const now = new Date();
  const pk = `${options.productId}:email:${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, '0')}`;

  // Render template
  let rendered: { subject: string; bodyHtml: string; bodyText: string };
  try {
    rendered = renderTemplate(options.templateId, options.variables);
  } catch (err: unknown) {
    const error = err instanceof Error ? err.message : String(err);
    log.error({ templateId: options.templateId, error }, '[delivery] Template render failed');
    return { success: false, error };
  }

  // Create pending log entry
  const logDoc: DeliveryLogDoc = {
    id: `del_${crypto.randomUUID()}`,
    productId: options.productId,
    pk,
    userId: options.userId,
    channel: 'email',
    templateId: options.templateId,
    to: options.to,
    subject: rendered.subject,
    status: 'pending',
    createdAt: now.toISOString(),
  };

  try {
    await repo.createDeliveryLog(logDoc);
  } catch {
    // Non-fatal — continue sending
  }

  // Send
  const result = await sendEmail(
    {
      to: options.to,
      from: config.fromEmail,
      fromName: config.fromName,
      subject: rendered.subject,
      bodyHtml: rendered.bodyHtml,
      bodyText: rendered.bodyText,
    },
    config,
    log
  );

  // Update log
  try {
    await repo.updateDeliveryLog({
      ...logDoc,
      status: result.success ? 'sent' : 'failed',
      sentAt: result.success ? new Date().toISOString() : undefined,
      error: result.error,
      metadata: result.messageId ? { messageId: result.messageId } : undefined,
    });
  } catch {
    // Non-fatal
  }

  return result;
}
