import { createHmac, timingSafeEqual } from "node:crypto";

export const DEVICE_URL_JWT_SECRET =
  "f8Kx9Qm2Vt7Nz4WpR1yLc6Hd3Js8BaEe";

type JwtHeader = {
  alg?: string;
  typ?: string;
};

type JwtPayload = {
  exp?: number;
  iat?: number;
  nbf?: number;
  [claim: string]: unknown;
};

function decodeJsonSegment<T>(segment: string): T {
  return JSON.parse(Buffer.from(segment, "base64url").toString("utf8")) as T;
}

export function verifyDeviceUrlToken(token: string): JwtPayload {
  const segments = token.split(".");

  if (segments.length !== 3 || segments.some((segment) => !segment)) {
    throw new Error("Malformed JWT");
  }

  const [encodedHeader, encodedPayload, encodedSignature] = segments;
  const header = decodeJsonSegment<JwtHeader>(encodedHeader);

  if (header.alg !== "HS256") {
    throw new Error("Unsupported JWT algorithm");
  }

  const signedContent = `${encodedHeader}.${encodedPayload}`;
  const expectedSignature = createHmac("sha256", DEVICE_URL_JWT_SECRET)
    .update(signedContent)
    .digest();
  const receivedSignature = Buffer.from(encodedSignature, "base64url");

  if (
    receivedSignature.length !== expectedSignature.length ||
    !timingSafeEqual(receivedSignature, expectedSignature)
  ) {
    throw new Error("Invalid JWT signature");
  }

  const payload = decodeJsonSegment<JwtPayload>(encodedPayload);
  const now = Math.floor(Date.now() / 1000);
  const clockToleranceSeconds = 30;

  if (!Number.isInteger(payload.exp)) {
    throw new Error("JWT must include an expiry");
  }

  if (payload.exp! <= now - clockToleranceSeconds) {
    throw new Error("JWT has expired");
  }

  if (
    payload.iat !== undefined &&
    (!Number.isInteger(payload.iat) ||
      payload.iat > now + clockToleranceSeconds)
  ) {
    throw new Error("JWT was issued in the future");
  }

  if (
    payload.nbf !== undefined &&
    (!Number.isInteger(payload.nbf) ||
      payload.nbf > now + clockToleranceSeconds)
  ) {
    throw new Error("JWT is not active");
  }

  return payload;
}
