import "server-only";

import { randomBytes } from "node:crypto";
import { EMAIL_VERIFICATION_TTL_MS } from "@/lib/auth/constants";
import { sendEmail } from "@/lib/email/smtp";
import { buildAppUrl } from "@/lib/http/url";
import { prisma } from "@/lib/prisma";

export async function issueEmailVerificationToken(userId: string) {
  const token = randomBytes(32).toString("hex");
  const expiresAt = new Date(Date.now() + EMAIL_VERIFICATION_TTL_MS);

  await prisma.emailVerificationToken.create({
    data: {
      userId,
      token,
      expiresAt,
    },
  });

  return { token, expiresAt };
}

export type SendVerificationResult = {
  sent: boolean;
  verificationUrl: string;
};

export async function sendEmailVerificationLink(request: Request, email: string, token: string) {
  const verificationUrl = buildAppUrl(request, "/verify", { token }).toString();

  try {
    await sendEmail({
      to: email,
      subject: "Verifica tu correo en Kontia",
      text: [
        "Gracias por registrarte en Kontia.",
        "",
        "Para verificar tu correo y activar tu cuenta, abre este enlace:",
        verificationUrl,
        "",
        "Si no solicitaste este registro, puedes ignorar este correo.",
      ].join("\n"),
      html: [
        "<p>Gracias por registrarte en <strong>Kontia</strong>.</p>",
        "<p>Para verificar tu correo y activar tu cuenta, haz clic en el siguiente enlace:</p>",
        `<p><a href="${verificationUrl}">Verificar mi correo</a></p>`,
        "<p>Si no solicitaste este registro, puedes ignorar este correo.</p>",
      ].join(""),
    });

    if (process.env.NODE_ENV !== "production") {
      console.log(`Verification email sent to ${email}: ${verificationUrl}`);
    }

    return {
      sent: true,
      verificationUrl,
    } satisfies SendVerificationResult;
  } catch (error) {
    console.error("Failed to send verification email", error);

    if (process.env.NODE_ENV !== "production") {
      console.log(`Verification email fallback for ${email}: ${verificationUrl}`);
    }

    return {
      sent: false,
      verificationUrl,
    } satisfies SendVerificationResult;
  }
}

type ConsumeEmailTokenResult = {
  status: "verified" | "expired_or_invalid";
  email?: string;
};

export async function consumeEmailVerificationToken(token: string): Promise<ConsumeEmailTokenResult> {
  const now = new Date();

  const verificationToken = await prisma.emailVerificationToken.findUnique({
    where: { token },
    include: {
      user: {
        select: {
          id: true,
          email: true,
        },
      },
    },
  });

  if (!verificationToken || verificationToken.consumedAt || verificationToken.expiresAt < now) {
    return { status: "expired_or_invalid" };
  }

  await prisma.$transaction([
    prisma.user.update({
      where: { id: verificationToken.user.id },
      data: { emailVerifiedAt: now },
    }),
    prisma.emailVerificationToken.update({
      where: { id: verificationToken.id },
      data: { consumedAt: now },
    }),
  ]);

  return {
    status: "verified",
    email: verificationToken.user.email,
  };
}
