import type { Transporter } from 'nodemailer';
import type { PilotLeadInput } from './pilot';
import { NIGHT_LABELS } from './pilot';

/**
 * Outbound email. With SMTP_URL set, mail goes out through nodemailer. Without it, nothing is sent
 * and the console says so plainly — we never pretend an email was delivered.
 *
 * Env: SMTP_URL (e.g. smtps://user:pass@smtp.example.com:465), MAIL_FROM, ADMIN_NOTIFY_EMAIL
 * (PILOT_NOTIFY_EMAIL overrides it for pilot leads).
 */

export interface MailMessage {
  to: string;
  subject: string;
  text: string;
  replyTo?: string;
}

export type MailResult =
  | { status: 'sent'; messageId: string }
  | { status: 'not-configured'; reason: string }
  | { status: 'failed'; error: string };

const DEFAULT_FROM = 'PintRush <no-reply@pintrush.com>';

const globalForMail = globalThis as unknown as { __pintrushMailer?: Promise<Transporter> };

async function transport(url: string): Promise<Transporter> {
  // Loaded lazily so the module (and its SMTP stack) is only pulled in when email is configured.
  globalForMail.__pintrushMailer ??= import('nodemailer').then(({ createTransport }) => createTransport(url));
  return globalForMail.__pintrushMailer;
}

/** Log an unsent message. Dev shows it in full so the flow can be checked; production logs no personal data. */
function logUnsent(message: MailMessage, reason: string): void {
  if (process.env.NODE_ENV === 'production') {
    console.warn(`[mailer] Email is NOT configured (${reason}) — "${message.subject}" was not sent.`);
    return;
  }
  const body = message.text
    .split('\n')
    .map((line) => `  | ${line}`)
    .join('\n');
  console.info(
    `[mailer] Email is NOT configured (${reason}) — nothing was sent. Message that would have gone out:\n` +
      `  To: ${message.to}\n  Subject: ${message.subject}\n${body}`,
  );
}

export async function sendMail(message: MailMessage): Promise<MailResult> {
  const url = process.env.SMTP_URL?.trim();
  if (!url) {
    const reason = 'SMTP_URL is not set';
    logUnsent(message, reason);
    return { status: 'not-configured', reason };
  }
  try {
    const transporter = await transport(url);
    const info = await transporter.sendMail({
      from: process.env.MAIL_FROM?.trim() || DEFAULT_FROM,
      to: message.to,
      subject: message.subject,
      text: message.text,
      ...(message.replyTo ? { replyTo: message.replyTo } : {}),
    });
    return { status: 'sent', messageId: String(info.messageId ?? '') };
  } catch (error) {
    const text = error instanceof Error ? error.message : String(error);
    console.error(`[mailer] Sending "${message.subject}" failed: ${text}`);
    return { status: 'failed', error: text };
  }
}

export function pilotLeadEmail(lead: PilotLeadInput & { id: string }): Omit<MailMessage, 'to'> {
  const lines = [
    `New PintRush pilot application (${lead.id})`,
    '',
    `Venue:        ${lead.venueName}`,
    `Address:      ${lead.address}`,
    `Contact:      ${lead.contactName}`,
    `Email:        ${lead.email}`,
    `Phone:        ${lead.phone ?? '—'}`,
    `TVs:          ${lead.tvCount}`,
    `Busy nights:  ${lead.busiestNights.map((night) => NIGHT_LABELS[night]).join(', ')}`,
    `Entertainment: ${lead.currentEntertainment ?? '—'}`,
    '',
    'Message:',
    lead.message ?? '—',
  ];
  return { subject: `Pilot application: ${lead.venueName}`, text: lines.join('\n'), replyTo: lead.email };
}

/** Tell the team about a new pilot lead. Never throws: the lead is already saved. */
export async function notifyAdminOfPilotLead(lead: PilotLeadInput & { id: string }): Promise<MailResult> {
  const to = (process.env.PILOT_NOTIFY_EMAIL || process.env.ADMIN_NOTIFY_EMAIL || process.env.ADMIN_EMAIL || '').trim();
  if (!to) {
    const reason = process.env.SMTP_URL?.trim()
      ? 'ADMIN_NOTIFY_EMAIL is not set'
      : 'SMTP_URL and ADMIN_NOTIFY_EMAIL are not set';
    logUnsent({ to: '(no recipient configured)', ...pilotLeadEmail(lead) }, `${reason}; lead ${lead.id} is saved — review it in /admin`);
    return { status: 'not-configured', reason };
  }
  return sendMail({ to, ...pilotLeadEmail(lead) });
}
