// src/lib/email.ts — transactional email via Resend.
import "server-only";
import { Resend } from "resend";
import { env } from "@/env";

const APP_NAME = "SEO Insight";
const APP_URL = process.env.BETTER_AUTH_URL || "http://localhost:3000";

// Instantiated only when email is fully configured (key + sender); otherwise we
// fall back to logging the actionable link to the console (usable in local dev).
const resend = env.emailEnabled ? new Resend(env.RESEND_API_KEY) : null;

/**
 * Send one email, or — when email isn't configured — log the link so the flow
 * still works locally. Never throws: a transport error must not break auth.
 */
async function deliver(opts: {
  to: string;
  subject: string;
  html: string;
  /** Short tag + the actionable URL, used for the dev console fallback. */
  kind: string;
  url: string;
}): Promise<void> {
  if (!resend) {
    console.log(`[email:dev] ${opts.kind} for ${opts.to} -> ${opts.url}`);
    return;
  }
  try {
    const { error } = await resend.emails.send({
      // Guaranteed defined: resend is only created when emailEnabled.
      from: env.EMAIL_FROM as string,
      to: opts.to,
      subject: opts.subject,
      html: opts.html,
    });
    if (error) {
      console.warn(
        `[email] ${opts.kind} send failed for ${opts.to}: ${error.message}`,
      );
    }
  } catch (e) {
    console.warn(
      `[email] ${opts.kind} send threw for ${opts.to}: ${e instanceof Error ? e.message : e}`,
    );
  }
}

function layout(body: string): string {
  return `<!doctype html>
<html lang="fr">
  <body style="font-family:system-ui,sans-serif;line-height:1.5;color:#0a0a0a">
    <h1 style="font-size:20px">${APP_NAME}</h1>
    ${body}
  </body>
</html>`;
}

function ctaButton(url: string, label: string): string {
  return `<p>
    <a href="${url}"
       style="display:inline-block;padding:10px 16px;background:#0a0a0a;color:#fff;border-radius:8px;text-decoration:none">
      ${label}
    </a>
  </p>
  <p style="color:#666;font-size:13px">Si le bouton ne marche pas, copie ce lien :<br />${url}</p>`;
}

/** Account-verification email, sent on sign-up. */
export async function sendVerificationEmail(opts: {
  to: string;
  url: string;
  name?: string | null;
}): Promise<void> {
  const hello = opts.name ? `Bonjour ${opts.name},` : "Bonjour,";
  await deliver({
    to: opts.to,
    kind: "verify-email",
    url: opts.url,
    subject: `Confirme ton adresse — ${APP_NAME}`,
    html: layout(
      `<p>${hello}</p><p>Confirme ton adresse email pour activer ton compte.</p>${ctaButton(opts.url, "Vérifier mon email")}`,
    ),
  });
}

/** Passwordless sign-in link. */
export async function sendMagicLinkEmail(opts: {
  to: string;
  url: string;
}): Promise<void> {
  await deliver({
    to: opts.to,
    kind: "magic-link",
    url: opts.url,
    subject: `Ton lien de connexion — ${APP_NAME}`,
    html: layout(
      `<p>Bonjour,</p><p>Clique pour te connecter à ${APP_NAME}. Ce lien expire bientôt.</p>${ctaButton(opts.url, "Se connecter")}`,
    ),
  });
}

/** Password-reset link. */
export async function sendResetPasswordEmail(opts: {
  to: string;
  url: string;
  name?: string | null;
}): Promise<void> {
  const hello = opts.name ? `Bonjour ${opts.name},` : "Bonjour,";
  await deliver({
    to: opts.to,
    kind: "reset-password",
    url: opts.url,
    subject: `Réinitialise ton mot de passe — ${APP_NAME}`,
    html: layout(
      `<p>${hello}</p><p>Tu as demandé à réinitialiser ton mot de passe.</p>${ctaButton(opts.url, "Choisir un nouveau mot de passe")}`,
    ),
  });
}

/** Confirmation link sent to the NEW address when a user changes their email. */
export async function sendChangeEmailEmail(opts: {
  to: string;
  url: string;
  name?: string | null;
}): Promise<void> {
  const hello = opts.name ? `Bonjour ${opts.name},` : "Bonjour,";
  await deliver({
    to: opts.to,
    kind: "change-email",
    url: opts.url,
    subject: `Confirme ta nouvelle adresse — ${APP_NAME}`,
    html: layout(
      `<p>${hello}</p><p>Confirme cette adresse pour l'utiliser sur ${APP_NAME}.</p>${ctaButton(opts.url, "Confirmer ma nouvelle adresse")}`,
    ),
  });
}

/** Confirmation link to finalize (irreversible) account deletion. */
export async function sendDeleteAccountEmail(opts: {
  to: string;
  url: string;
  name?: string | null;
}): Promise<void> {
  const hello = opts.name ? `Bonjour ${opts.name},` : "Bonjour,";
  await deliver({
    to: opts.to,
    kind: "delete-account",
    url: opts.url,
    subject: `Confirme la suppression de ton compte — ${APP_NAME}`,
    html: layout(
      `<p>${hello}</p><p>Tu as demandé à supprimer ton compte ${APP_NAME}. Cette action est définitive et irréversible.</p>${ctaButton(opts.url, "Supprimer définitivement mon compte")}`,
    ),
  });
}

/** Organization invitation link. */
export async function sendInvitationEmail(opts: {
  to: string;
  url: string;
  orgName: string;
  inviterName?: string | null;
  role?: string | null;
}): Promise<void> {
  const who = opts.inviterName
    ? `${opts.inviterName} t'invite`
    : "Tu es invité";
  const asRole = opts.role ? ` en tant que ${opts.role}` : "";
  await deliver({
    to: opts.to,
    kind: "invitation",
    url: opts.url,
    subject: `Invitation à rejoindre ${opts.orgName} — ${APP_NAME}`,
    html: layout(
      `<p>Bonjour,</p><p>${who} à rejoindre <strong>${opts.orgName}</strong>${asRole} sur ${APP_NAME}.</p>${ctaButton(opts.url, "Rejoindre l'organisation")}`,
    ),
  });
}

/**
 * Seat-blocked admin nudge (seat flow S2): someone tried to accept an
 * invitation but the org has no seat left. Sent to the org's owner + admins,
 * deduped per invitation via `invitation.seatBlockNotifiedAt`.
 */
export async function sendSeatBlockedEmail(opts: {
  to: string;
  orgName: string;
  /** Plan of the org's subscription — null on trial/expired orgs. */
  plan: string | null;
  /** Address of the person who tried to join. */
  attemptEmail: string;
}): Promise<void> {
  const url = `${APP_URL}/settings/billing`;
  const planLabel = opts.plan ? `le plan ${opts.plan}` : "le plan actuel";
  await deliver({
    to: opts.to,
    kind: "seat-blocked",
    url,
    subject: `${opts.attemptEmail} attend une place dans ${opts.orgName}`,
    html: layout(
      `<p>Bonjour,</p><p><strong>${opts.attemptEmail}</strong> a tenté de rejoindre <strong>${opts.orgName}</strong>, mais il n'y a plus de siège disponible sur ${planLabel}. Augmente ton plan pour l'accueillir.</p>${ctaButton(url, "Augmenter le plan")}`,
    ),
  });
}

/** Seat-flow S3: tell a blocked invitee that a seat is now free (post-upgrade). */
export async function sendSeatFreedEmail(opts: {
  to: string;
  orgName: string;
  invitationId: string;
}): Promise<void> {
  const url = `${APP_URL}/accept-invitation/${opts.invitationId}`;
  await deliver({
    to: opts.to,
    kind: "seat-freed",
    url,
    subject: `Une place s'est libérée dans ${opts.orgName}`,
    html: layout(
      `<p>Bonjour,</p><p>Bonne nouvelle : une place s'est libérée dans <strong>${opts.orgName}</strong>. Tu peux maintenant accepter ton invitation et rejoindre l'équipe.</p>${ctaButton(url, `Rejoindre ${opts.orgName}`)}`,
    ),
  });
}
