import type { AudioBookUsage } from "./types";

export const R2_SOFT_LIMIT_BYTES = 8 * 1024 * 1024 * 1024;
export const MAX_AUDIO_BOOKS = 5;

function oldestFirst(audioBooks: readonly AudioBookUsage[]): AudioBookUsage[] {
  return [...audioBooks].sort((left, right) => {
    const timeDifference = Date.parse(left.lastUsedAt) - Date.parse(right.lastUsedAt);
    return timeDifference || left.bookId.localeCompare(right.bookId);
  });
}

export function planAudioRetention(
  audioBooks: readonly AudioBookUsage[],
  requestedBookId: string,
): string[] {
  const requestedAlreadyCached = audioBooks.some(
    (entry) => entry.bookId === requestedBookId,
  );
  const allowedExistingCount = requestedAlreadyCached
    ? MAX_AUDIO_BOOKS
    : MAX_AUDIO_BOOKS - 1;
  const removable = oldestFirst(audioBooks).filter(
    (entry) => entry.bookId !== requestedBookId,
  );
  return removable
    .slice(0, Math.max(0, audioBooks.length - allowedExistingCount))
    .map((entry) => entry.bookId);
}

export function planStorageAdmission(input: {
  usedBytes: number;
  pendingBytes: number;
  audioBooks: readonly AudioBookUsage[];
}): {
  allowed: boolean;
  evictBookIds: string[];
  bytesAfter: number;
} {
  const usedBytes = Math.max(0, Math.round(input.usedBytes));
  const pendingBytes = Math.max(0, Math.round(input.pendingBytes));
  let bytesAfter = usedBytes + pendingBytes;
  const evictBookIds: string[] = [];

  if (bytesAfter > R2_SOFT_LIMIT_BYTES) {
    for (const audioBook of oldestFirst(input.audioBooks)) {
      evictBookIds.push(audioBook.bookId);
      bytesAfter -= Math.max(0, Math.round(audioBook.bytes));
      if (bytesAfter <= R2_SOFT_LIMIT_BYTES) break;
    }
  }

  return {
    allowed: bytesAfter <= R2_SOFT_LIMIT_BYTES,
    evictBookIds,
    bytesAfter,
  };
}
