import { BadRequestException } from "@nestjs/common";

/**
 * Keyset cursor for paging a thread backwards from newest.
 *
 * The cursor is just a message id. The sort key is the pair `(created_at, id)` —
 * two messages can share a timestamp, and a cursor on a non-unique key either
 * re-serves or skips the tied rows — but the *timestamp half is never sent over
 * the wire*, because it cannot survive the trip.
 *
 * `support_messages.created_at` is `timestamptz(6)`; a JS `Date` holds only
 * milliseconds, so the value TypeORM hands back is already truncated. Encoding
 * that into the cursor and comparing against it would silently skip every row
 * sharing the cursor's millisecond but earlier within it (`.254100` is not
 * `< .254000`) — those rows would never appear on any page. Sending the id alone
 * and letting Postgres look the real `(created_at, id)` up keeps the comparison
 * at full precision on the server, where it was never lossy.
 *
 * Opaque on purpose (base64): clients must treat it as a token, so the sort key
 * can change without a contract change.
 *
 * The passenger API's twin encodes a timestamp because its column is
 * `TIMESTAMP(3)` — millisecond, matching JS exactly — so it has no such loss.
 * The two formats are deliberately NOT interchangeable; each app reads only its
 * own cursors.
 */
export function encodeMessageCursor(id: string): string {
  return Buffer.from(id, "utf8").toString("base64url");
}

/**
 * Parse a client-supplied cursor. Rejects anything malformed rather than
 * silently falling back to "first page" — a corrupted cursor that degrades to
 * page 1 makes an infinite scroll loop forever over the same rows.
 */
export function decodeMessageCursor(raw: string): string {
  let id: string;
  try {
    id = Buffer.from(raw, "base64url").toString("utf8");
  } catch {
    throw new BadRequestException("Malformed pagination cursor.");
  }

  // The id goes into a parameterized query, but validate the shape anyway: a
  // non-uuid can only be a mangled cursor, and failing loudly here beats an
  // empty page that reads as "start of conversation".
  if (
    !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)
  ) {
    throw new BadRequestException("Malformed pagination cursor.");
  }

  return id;
}
