import { createHash } from "crypto";

import { headers } from "next/headers";

import { prisma } from "@/lib/prisma";
import {
  CONTACT_RATE_LIMIT_KEY_PREFIX,
  type ContactProtectionSettings,
} from "@/lib/contact-protection";

async function getClientIpFromHeaders() {
  const requestHeaders = await headers();
  const forwardedFor = requestHeaders.get("x-forwarded-for");

  if (forwardedFor) {
    return forwardedFor.split(",")[0]?.trim() || "unknown";
  }

  return requestHeaders.get("x-real-ip")?.trim() || "unknown";
}

function getRateLimitKey(ip: string, windowMinutes: number) {
  const windowMs = windowMinutes * 60 * 1000;
  const windowStart = Math.floor(Date.now() / windowMs) * windowMs;
  const ipHash = createHash("sha256").update(ip).digest("hex");

  return `${CONTACT_RATE_LIMIT_KEY_PREFIX}:${ipHash}:${windowStart}`;
}

function parseCount(rawValue: string | null | undefined) {
  if (!rawValue) {
    return 0;
  }

  const parsed = Number.parseInt(rawValue, 10);
  return Number.isInteger(parsed) && parsed >= 0 ? parsed : 0;
}

export async function enforceContactRateLimit(settings: ContactProtectionSettings) {
  if (!settings.rateLimit.enabled) {
    return;
  }

  const ip = await getClientIpFromHeaders();
  const key = getRateLimitKey(ip, settings.rateLimit.windowMinutes);

  await prisma.$transaction(async (tx) => {
    const current = await tx.appConfig.findUnique({
      where: { key },
      select: { value: true },
    });
    const nextCount = parseCount(current?.value) + 1;

    if (nextCount > settings.rateLimit.maxRequests) {
      throw new Error("Too many contact requests. Please try again later.");
    }

    await tx.appConfig.upsert({
      where: { key },
      update: {
        value: String(nextCount),
      },
      create: {
        key,
        value: "1",
      },
    });
  });
}

export async function verifyTurnstileToken(
  settings: ContactProtectionSettings,
  token: string,
) {
  if (!settings.turnstile.enabled) {
    return;
  }

  if (!settings.turnstile.siteKey || !settings.turnstile.secretKey) {
    throw new Error("Turnstile is enabled but not fully configured.");
  }

  if (!token.trim()) {
    throw new Error("Turnstile verification is required.");
  }

  const body = new URLSearchParams();
  body.set("secret", settings.turnstile.secretKey);
  body.set("response", token);
  body.set("remoteip", await getClientIpFromHeaders());

  const response = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body,
    cache: "no-store",
  });

  if (!response.ok) {
    throw new Error("Turnstile verification request failed.");
  }

  const result = await response.json() as {
    success?: boolean;
  };

  if (!result.success) {
    throw new Error("Turnstile verification failed.");
  }
}
