import { BookRepository } from "./repositories/books.ts";
import { ChapterRepository } from "./repositories/chapters.ts";
import { createChapterApi } from "./chapter-api.ts";
import { D1UploadSessionStore } from "./repositories/uploads.ts";
import { createUploadApi } from "./upload-api.ts";
import { createUploadCoordinator, type MultipartBucket } from "./uploads.ts";
import { getBindings } from "./env.ts";
import { AudioRepository } from "./repositories/audio.ts";
import { createAudioApi } from "./audio-api.ts";
import { ProgressRepository } from "./repositories/progress.ts";
import { createProgressApi } from "./progress-api.ts";
import { StorageRepository } from "./repositories/storage.ts";
import { createStorageApi } from "./storage-api.ts";
import { createCoverApi } from "./cover-api.ts";
import { RateLimitRepository } from "./rate-limit.ts";

export function getBookRepository(): BookRepository {
  return new BookRepository(getBindings().DB);
}

export function getUploadApi() {
  const bindings = getBindings();
  const books = new BookRepository(bindings.DB);
  const coordinator = createUploadCoordinator({
    store: new D1UploadSessionStore(bindings.DB),
    bucket: bindings.STORAGE as unknown as MultipartBucket,
    assertStorageAdmission: (bytes) => new StorageRepository(bindings.DB).assertSourceAdmission(bytes),
  });
  return createUploadApi({
    coordinator,
    registerCompletedBook: (session) => books.registerCompletedUpload(session),
  });
}

export function getChapterApi() {
  const bindings = getBindings();
  return createChapterApi(
    new ChapterRepository(bindings.DB),
    async (keys) => {
      for (let index = 0; index < keys.length; index += 1000) {
        await bindings.STORAGE.delete(keys.slice(index, index + 1000));
      }
    },
  );
}

export function getAudioApi() {
  const bindings = getBindings();
  return createAudioApi({
    repository: new AudioRepository(bindings.DB),
    bucket: bindings.STORAGE as unknown as Parameters<typeof createAudioApi>[0]["bucket"],
  });
}

export function getProgressApi() {
  return createProgressApi(new ProgressRepository(getBindings().DB));
}

export function getStorageApi() {
  return createStorageApi(new StorageRepository(getBindings().DB));
}

export function getCoverApi() {
  const bindings = getBindings();
  return createCoverApi({
    repository: new BookRepository(bindings.DB),
    bucket: bindings.STORAGE,
    assertStorageAdmission: (bytes, reclaimableBytes) =>
      new StorageRepository(bindings.DB).assertAdmission(bytes, reclaimableBytes),
  });
}

export function getRateLimiter() {
  return new RateLimitRepository(getBindings().DB);
}
