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

/**
 * Keyset cursor for paging a thread backwards from newest.
 *
 * The sort key is the pair `(createdAt, id)`, not `createdAt` alone: two
 * messages can share a millisecond, and a cursor on a non-unique key either
 * re-serves or skips the tied rows depending which side of the boundary they
 * land on. The id breaks ties with a stable total order.
 *
 * Deliberately a twin of the freight API's `message-cursor.ts`, not a shared
 * import: the two APIs share no runtime package, and @edr/types is Nest-free by
 * design (this throws Nest exceptions). The wire format matches so a client can
 * treat both chats identically — keep them in step if either changes.
 */
export interface MessageCursor {
  createdAt: Date;
  id: string;
}

export function encodeMessageCursor(cursor: MessageCursor): string {
  return Buffer.from(`${cursor.createdAt.toISOString()}|${cursor.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): MessageCursor {
  let decoded: string;
  try {
    decoded = Buffer.from(raw, 'base64url').toString('utf8');
  } catch {
    throw new BadRequestException('Malformed pagination cursor.');
  }

  const separator = decoded.lastIndexOf('|');
  if (separator === -1) {
    throw new BadRequestException('Malformed pagination cursor.');
  }

  const createdAt = new Date(decoded.slice(0, separator));
  const id = decoded.slice(separator + 1);
  if (Number.isNaN(createdAt.getTime()) || !id) {
    throw new BadRequestException('Malformed pagination cursor.');
  }

  return { createdAt, id };
}
