import "server-only";
import { Resend } from "resend";
import { db } from "@/lib/db/client";
import { emailLog } from "@/lib/db/schema";
import { loadEnv } from "@/lib/env";
import { loadTemplate, renderTemplate } from "./templates-db";

export type EmailMessage = {
  to: string | string[];
  subject: string;
  text: string;
  templateSlug?: string;
};

export type TemplatedEmailMessage = {
  to: string | string[];
  templateSlug: string;
  variables: Record<string, string | number | null | undefined>;
};

async function persistLog(rows: Array<Parameters<typeof db.insert>[0] extends never ? never : typeof emailLog.$inferInsert>) {
  if (rows.length === 0) return;
  try {
    await db.insert(emailLog).values(rows);
  } catch (err) {
    console.error("[email-log] failed to persist delivery log", err);
  }
}

/**
 * Send an already-composed email (subject + plain-text body). Adds a row to
 * `email_log` so the admin panel can show delivery history.
 */
export async function sendEmail(msg: EmailMessage): Promise<void> {
  const env = loadEnv();
  const recipients = Array.isArray(msg.to) ? msg.to : [msg.to];
  const bodyPreview = msg.text.slice(0, 500);

  if (!env.resendApiKey) {
    // Dev mode — no mailer configured. Surface the message in logs AND in
    // the admin email log so the team can copy-paste links to test.
    console.log("[email:dev]", JSON.stringify(msg, null, 2));
    await persistLog(
      recipients.map((r) => ({
        recipient: r,
        subject: msg.subject,
        templateSlug: msg.templateSlug ?? null,
        status: "dev_console" as const,
        bodyPreview,
        sentAt: new Date(),
      })),
    );
    return;
  }

  const resend = new Resend(env.resendApiKey);
  try {
    const { data, error } = await resend.emails.send({
      from: env.emailFrom,
      to: recipients,
      subject: msg.subject,
      text: msg.text,
    });
    if (error) throw new Error(`Resend error: ${error.message}`);
    await persistLog(
      recipients.map((r) => ({
        recipient: r,
        subject: msg.subject,
        templateSlug: msg.templateSlug ?? null,
        status: "sent" as const,
        providerId: data?.id ?? null,
        bodyPreview,
        sentAt: new Date(),
      })),
    );
  } catch (err) {
    const errorMessage = err instanceof Error ? err.message : String(err);
    await persistLog(
      recipients.map((r) => ({
        recipient: r,
        subject: msg.subject,
        templateSlug: msg.templateSlug ?? null,
        status: "failed" as const,
        errorMessage,
        bodyPreview,
      })),
    );
    throw err;
  }
}

/**
 * Compose + send an email by template slug. Looks up the latest admin-edited
 * template (falling back to built-in defaults), renders {{variables}}, and
 * routes through {@link sendEmail} so delivery is logged.
 */
export async function sendTemplatedEmail(msg: TemplatedEmailMessage): Promise<void> {
  const tpl = await loadTemplate(msg.templateSlug);
  const { subject, body } = renderTemplate(tpl, msg.variables);
  await sendEmail({ to: msg.to, subject, text: body, templateSlug: msg.templateSlug });
}
