import fs from "node:fs/promises";
import util from "node:util";
import { chromium } from "./browser";
import { createDatabase } from "./database";
import { createLibrary } from "./library";
import { createPlatform } from "./platform";

const options = {
  db: {
    type: "string",
    default: "gadl.db",
  },
  "out-dir": {
    type: "string",
    default: "dist",
  },
  reset: {
    type: "boolean",
    async run() {
      await fs.rm(args.values.db!);
    },
  },
  login: {
    type: "boolean",
    async run() {
      const db = await createDatabase(args.values.db!);
      const browser = await chromium.launch({ headless: false });
      const platform = createPlatform({ db, browser });
      await platform.login();
    },
  },
  logout: {
    type: "boolean",
    async run() {
      const db = await createDatabase(args.values.db!);
      const browser = await chromium.launch();
      const platform = createPlatform({ db, browser });
      await platform.logout();
    },
  },
  add: {
    type: "string",
    async run() {
      const db = await createDatabase(args.values.db!);
      const library = createLibrary(db);
      await library.add(args.values.add!);
    },
  },
  delete: {
    type: "string",
    async run() {
      const db = await createDatabase(args.values.db!);
      const library = createLibrary(db);
      await library.delete(Number(args.values.delete));
    },
  },
  list: {
    type: "boolean",
    short: "l",
    async run() {
      const db = await createDatabase(args.values.db!);
      const library = createLibrary(db);
      const books = await library.getBooks();

      console.dir(books, {
        depth: null,
        maxArrayLength: null,
        maxStringLength: null,
      });
    },
  },
  view: {
    type: "string",
    async run() {
      const db = await createDatabase(args.values.db!);
      const library = createLibrary(db);
      const book = await library.get(Number(args.values.view!));

      if (!book) {
        process.exit(1);
      }

      console.dir(book, {
        depth: null,
        maxArrayLength: null,
        maxStringLength: null,
      });
    },
  },
  pull: {
    type: "boolean",
    async run() {
      const db = await createDatabase(args.values.db!);
      const library = createLibrary(db);
      const browser = await chromium.launch();
      const platform = createPlatform({ db, browser });

      for await (const book of platform.pull()) {
        await library.add(book);
      }
    },
  },
  download: {
    type: "string",
    async run() {
      const db = await createDatabase(args.values.db!);
      const library = createLibrary(db);
      const book = await library.get(Number(args.values.download!));

      if (!book) {
        process.exit(1);
      }

      const browser = await chromium.launch();
      const platform = createPlatform({ db, browser });
      const dir = `${args.values["out-dir"]!}/${book.id}`;
      await platform.download(dir, book);
      await library.archive(args.values["out-dir"]!);
    },
  },
  archive: {
    type: "boolean",
    async run() {
      const db = await createDatabase(args.values.db!);
      const library = createLibrary(db);
      await library.archive(args.values["out-dir"]!);
    },
  },
  help: {
    type: "boolean",
    short: "h",
    run() {
      console.log(
        [
          "Available options:",
          ...Object.keys(options).map((option) => `  --${option}`),
        ].join("\n"),
      );
    },
  },
} as const;

const args = util.parseArgs({ options });

for (const option of Object.keys(options)) {
  if (args.values[option] && typeof options[option].run === "function") {
    await options[option].run();
    process.exit();
  }
}