// PAM approval-email sender.
//
// `manual`-mode privilege requests send a mail to the policy's
// `approver_email` containing a one-click approval link. The link
// targets /api/pam/approve/<token>; the token is single-use and
// rotates the grant's status from `pending` → `active`.
//
// SMTP is configured via env vars (all optional):
//   PAM_SMTP_HOST, PAM_SMTP_PORT (default 587),
//   PAM_SMTP_USER, PAM_SMTP_PASSWORD,
//   PAM_SMTP_FROM (default 'no-reply@gosec.cloud'),
//   PAM_SMTP_SECURE ('true' for implicit TLS, default false → STARTTLS).
//
// If PAM_SMTP_HOST is unset, sendApprovalEmail() throws — manual-mode
// request handlers should catch this and refuse the request with a
// clear error so the user knows to ask an operator to configure SMTP.

import nodemailer from "nodemailer";

export interface ApprovalEmailInput {
  to: string;
  approveUrl: string;
  requesterDisplay: string;     // "Olivia Smith <olivia.smith@…>" or just gscsid
  roleName: string;
  durationHours: number;
  justification: string;
}

export function isMailConfigured(): boolean {
  return !!process.env.PAM_SMTP_HOST;
}

let cachedTransport: nodemailer.Transporter | null = null;

function getTransport(): nodemailer.Transporter {
  if (cachedTransport) return cachedTransport;
  const host = process.env.PAM_SMTP_HOST;
  if (!host) {
    throw new Error(
      "SMTP not configured — set PAM_SMTP_HOST (and PAM_SMTP_USER/PAM_SMTP_PASSWORD if auth is required) to enable manual-mode PAM approvals.",
    );
  }
  cachedTransport = nodemailer.createTransport({
    host,
    port: parseInt(process.env.PAM_SMTP_PORT ?? "587", 10),
    secure: process.env.PAM_SMTP_SECURE === "true",
    auth: process.env.PAM_SMTP_USER
      ? {
          user: process.env.PAM_SMTP_USER,
          pass: process.env.PAM_SMTP_PASSWORD ?? "",
        }
      : undefined,
  });
  return cachedTransport;
}

export async function sendApprovalEmail(input: ApprovalEmailInput): Promise<void> {
  const t = getTransport();
  const from = process.env.PAM_SMTP_FROM ?? "no-reply@gosec.cloud";
  const subject = `[PAM] Approval required: ${input.roleName} for ${input.requesterDisplay}`;
  const text = [
    `${input.requesterDisplay} has requested privileged role:`,
    "",
    `  Role:           ${input.roleName}`,
    `  Duration:       ${input.durationHours} hour(s)`,
    `  Justification:  ${input.justification}`,
    "",
    `Approve:  ${input.approveUrl}`,
    "",
    "If you didn't expect this request, ignore the link — it will expire",
    "in 24 hours and the grant will not activate.",
  ].join("\n");
  const html = `
    <p><strong>${escapeHtml(input.requesterDisplay)}</strong> has requested a privileged role.</p>
    <table style="border-collapse:collapse;font-family:sans-serif">
      <tr><td style="padding:4px 8px;color:#666">Role</td><td style="padding:4px 8px"><code>${escapeHtml(input.roleName)}</code></td></tr>
      <tr><td style="padding:4px 8px;color:#666">Duration</td><td style="padding:4px 8px">${input.durationHours} hour(s)</td></tr>
      <tr><td style="padding:4px 8px;color:#666;vertical-align:top">Justification</td><td style="padding:4px 8px">${escapeHtml(input.justification)}</td></tr>
    </table>
    <p style="margin-top:24px">
      <a href="${escapeHtml(input.approveUrl)}"
         style="display:inline-block;padding:10px 18px;background:#0066cc;color:#fff;text-decoration:none;border-radius:4px">
        Approve request
      </a>
    </p>
    <p style="color:#888;font-size:12px">If you didn't expect this request, ignore the link — it expires in 24 hours.</p>
  `;
  await t.sendMail({ from, to: input.to, subject, text, html });
}

function escapeHtml(s: string): string {
  return s
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#39;");
}
