import { LibraryBackend } from "~/prisma/client/enums";
import prisma from "../internal/db/database";
import type { JsonValue } from "@prisma/client/runtime/library";
import type { LibraryProvider } from "../internal/library/provider";
import type { FilesystemProviderConfig } from "../internal/library/providers/filesystem";
import { FilesystemProvider } from "../internal/library/providers/filesystem";
import libraryManager from "../internal/library";
import path from "path";
import { FlatFilesystemProvider } from "../internal/library/providers/flat";
import { logger } from "~/server/internal/logging";

export const libraryConstructors: {
  [key in LibraryBackend]: (
    value: JsonValue,
    id: string,
  ) => LibraryProvider<unknown>;
} = {
  Filesystem: function (
    value: JsonValue,
    id: string,
  ): LibraryProvider<unknown> {
    return new FilesystemProvider(value, id);
  },
  FlatFilesystem: function (
    value: JsonValue,
    id: string,
  ): LibraryProvider<unknown> {
    return new FlatFilesystemProvider(value, id);
  },
};

export default defineNitroPlugin(async () => {
  let successes = 0;
  const libraries = await prisma.library.findMany({});

  // Add migration handler
  const legacyPath = process.env.LIBRARY;
  if (legacyPath && libraries.length == 0) {
    const options: typeof FilesystemProviderConfig.infer = {
      baseDir: path.resolve(legacyPath),
    };

    const library = await prisma.library.create({
      data: {
        name: "Auto-created",
        backend: LibraryBackend.Filesystem,
        options,
      },
    });

    libraries.push(library);

    // Update all existing games
    await prisma.game.updateMany({
      where: {
        libraryId: null,
      },
      data: {
        libraryId: library.id,
      },
    });
  }

  // Delete all games that don't have a library provider after the legacy handler
  // (leftover from a bug)
  await prisma.game.deleteMany({
    where: {
      libraryId: null,
    },
  });

  for (const library of libraries) {
    const constructor = libraryConstructors[library.backend];
    try {
      const provider = constructor(library.options, library.id);
      libraryManager.addLibrary(provider);
      successes++;
    } catch (e) {
      logger.warn(
        `Failed to create library (${library.id}) of type ${library.backend}:\n ${e}`,
      );
    }
  }

  if (successes == 0) {
    logger.warn(
      "No library was successfully initialised. Please check for errors. If you have just set up an instance, this is normal.",
    );
  }
});
