import { createHash, randomBytes } from "crypto";

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

const RESET_TOKEN_TTL_MS = 1000 * 60 * 30;

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

export function getAppBaseUrl() {
  return getAppUrlOrThrow();
}

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

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

  return {
    plainToken,
    expiresAt
  };
}

export async function consumePasswordResetToken(token: string) {
  const tokenHash = hashToken(token);
  const resetToken = await prisma.passwordResetToken.findUnique({
    where: { tokenHash },
    include: {
      user: {
        include: {
          role: true
        }
      }
    }
  });

  if (!resetToken) {
    return null;
  }

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

  return resetToken;
}

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

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