import { createHash, randomBytes } from "crypto";

import { prisma } from "@/lib/prisma";
import { getAppUrlOrThrow } from "@/lib/runtime-env";

const VERIFY_TOKEN_TTL_MS = 1000 * 60 * 60 * 24;

function hashToken(token: string) {
  return createHash("sha256").update(token).digest("hex");
}

function getAppBaseUrl() {
  return getAppUrlOrThrow();
}

export async function issueEmailVerificationToken(userId: bigint) {
  const plainToken = randomBytes(32).toString("hex");
  const tokenHash = hashToken(plainToken);
  const expiresAt = new Date(Date.now() + VERIFY_TOKEN_TTL_MS);

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

  return {
    plainToken,
    expiresAt
  };
}

export async function consumeEmailVerificationToken(token: string) {
  const tokenHash = hashToken(token);
  const verificationToken = await prisma.emailVerificationToken.findUnique({
    where: { tokenHash },
    include: {
      user: true
    }
  });

  if (!verificationToken) {
    return null;
  }

  if (verificationToken.usedAt || verificationToken.expiresAt.getTime() < Date.now()) {
    return null;
  }

  return verificationToken;
}

export async function markEmailVerificationTokenUsed(id: bigint) {
  await prisma.emailVerificationToken.update({
    where: { id },
    data: {
      usedAt: new Date()
    }
  });
}

export function buildEmailVerificationUrl(token: string) {
  const url = new URL("/verify-email", getAppBaseUrl());
  url.searchParams.set("token", token);
  return url.toString();
}
