import nodemailer from 'nodemailer';
import type pg from 'pg';

const SMTP_KEYS = ['smtp_host', 'smtp_port', 'smtp_secure', 'smtp_user', 'smtp_pass', 'smtp_from'] as const;

export const ORDER_STATE_LABELS: Record<string, string> = {
  PENDING: 'Pendiente',
  AWAITING_PAYMENT: 'Esperando pago',
  PAID: 'Pagado',
  PROCESSING: 'En preparación',
  SHIPPED: 'Enviado',
  DELIVERED: 'Entregado',
  CANCELLED: 'Cancelado',
  REFUNDED: 'Reembolsado',
  PARTIALLY_REFUNDED: 'Reembolso parcial',
};

function escapeHtml(value: string): string {
  return value.replace(/[&<>"']/g, (character) => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
  })[character] ?? character);
}

export interface OrderStatusNotificationInput {
  to: string;
  orderId: string;
  state: string;
  trackingNumber?: string | null;
  courier?: string | null;
}

/**
 * Sends order status change emails through the SMTP configuration stored in
 * store_settings (Ajustes → SMTP / Email), with env fallback. Failures are
 * thrown so callers can report `notified: false` without breaking the flow.
 */
export async function sendOrderStatusEmail(
  pool: pg.Pool,
  input: OrderStatusNotificationInput,
): Promise<void> {
  const result = await pool.query<{ key: string; value: string }>(
    `SELECT key, value FROM store_settings WHERE key = ANY($1::text[])`,
    [SMTP_KEYS],
  );
  const settings = Object.fromEntries(result.rows.map((row) => [row.key, row.value]));
  const host = settings.smtp_host?.trim() || process.env.SMTP_HOST?.trim();
  const user = settings.smtp_user?.trim() || process.env.SMTP_USER?.trim();
  const password = settings.smtp_pass || process.env.SMTP_PASS;
  const from = settings.smtp_from?.trim() || process.env.SMTP_FROM?.trim() || user;
  if (!host || !user || !password || !from) {
    throw new Error('SMTP is not configured in Ajustes → SMTP / Email');
  }
  const port = Number(settings.smtp_port || process.env.SMTP_PORT || '465');
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
    throw new Error('SMTP port is invalid in Ajustes → SMTP / Email');
  }

  const transporter = nodemailer.createTransport({
    host,
    port,
    secure: (settings.smtp_secure ?? process.env.SMTP_SECURE) !== 'false' || port === 465,
    auth: { user, pass: password },
  });

  await transporter.sendMail({
    from,
    to: input.to,
    ...buildOrderStatusEmail(input),
  });
}

/**
 * Builds the status-change email body. Pure function so the courier/tracking
 * content can be unit tested without SMTP.
 */
export function buildOrderStatusEmail(input: OrderStatusNotificationInput): {
  subject: string;
  text: string;
  html: string;
} {
  const shortId = input.orderId.slice(0, 8);
  const stateLabel = ORDER_STATE_LABELS[input.state] ?? input.state;
  const courierLine = input.courier?.trim() ? `Transportista: ${input.courier.trim()}` : '';
  const trackingLine = input.trackingNumber
    ? `Número de seguimiento: ${input.trackingNumber}`
    : '';

  return {
    subject: `Tu pedido #${shortId} ahora está: ${stateLabel} — Mercado de Vida`,
    text: [
      `Hola,`,
      '',
      `Tu pedido #${shortId} ha cambiado de estado: ${stateLabel}.`,
      courierLine,
      trackingLine,
      '',
      'Puedes consultar el detalle desde tu cuenta en mercadodevida.',
      '',
      'Gracias por tu compra.',
    ]
      .filter((line) => line !== '')
      .join('\n'),
    html: [
      `<p>Hola,</p>`,
      `<p>Tu pedido <strong>#${escapeHtml(shortId)}</strong> ha cambiado de estado: <strong>${escapeHtml(stateLabel)}</strong>.</p>`,
      courierLine ? `<p>Transportista: <strong>${escapeHtml(input.courier ?? '')}</strong></p>` : '',
      trackingLine ? `<p>Número de seguimiento: <strong>${escapeHtml(input.trackingNumber ?? '')}</strong></p>` : '',
      `<p>Puedes consultar el detalle desde tu cuenta en mercadodevida.</p>`,
      `<p>Gracias por tu compra.</p>`,
    ]
      .filter((line) => line !== '')
      .join(''),
  };
}
