import type { Book } from "../library";
import type { Browser, BrowserContext, ImageFile } from "../browser";
import { getImageFiles } from "./dmm-books";

export function FanzaDoujin(browser: Browser) {
  async function* getAllBooks(ctx: BrowserContext): AsyncGenerator<Book> {
    const endpoint =
      "https://www.dmm.co.jp/dc/doujin/api/mylibraries/?limit=20";
    const pager = {
      page: 1,
      perPage: 20,
      totalCount: Infinity,
    };

    while ((pager.page - 1) * pager.perPage <= pager.totalCount) {
      const res = await ctx.request.get(`${endpoint}&page=${pager.page}`);

      if (!res.ok()) {
        throw new Error(`${res.status()} ${res.statusText()}`);
      }

      const body: {
        data: {
          items: Record<
            string,
            Array<{
              productId: string;
              title: string;
              makerName: string;
            }>
          >;
          total: number;
        };
      } = await res.json();

      for (const item of Object.values(body.data.items).flat()) {
        yield {
          id: NaN,
          platform: "fanza-doujin",
          readerUrl: `https://www.dmm.co.jp/dc/-/mylibrary/detail/=/product_id=${item.productId}/`,
          title: item.title || "",
          authors: [item.makerName],
        };

        process.stderr.write(".");
      }

      pager.page += 1;
      pager.totalCount = body.data.total;
    }
  }

  return {
    async *pull(): AsyncGenerator<Book> {
      const ctx = await browser.loadBrowserContext("fanza-doujin");

      yield* getAllBooks(ctx);

      process.stderr.write(`\n`);
    },

    async getFiles(book: Book): Promise<Array<() => Promise<Blob>>> {
      const ctx = await browser.loadBrowserContext("fanza-doujin");
      const page = await ctx.newPage();

      await page.goto(book.readerUrl);

      const [, productId] = /product_id=([^/]*)/.exec(book.readerUrl) ?? [];

      if (!productId) {
        throw new Error(`product_id is not included: ${book.readerUrl}`);
      }

      const res = await ctx.request.get(
        `https://www.dmm.co.jp/dc/doujin/api/mylibraries/details/${productId}/`,
      );

      if (!res.ok()) {
        throw new Error(`${res.status()} ${res.statusText()}`);
      }

      const body: {
        data: {
          drm: {
            dmmBooks: boolean;
            softDenchi: boolean;
          };
          downloadLinks: Record<number, string>;
        };
      } = await res.json();

      const imageFiles: Array<ImageFile> = [];

      if (body.data.drm.dmmBooks) {
        await page.waitForSelector(`li[class^="fileTreeItem"]`);
        await page.click(`li[class^="fileTreeItem"]>a`);
        await page.waitForURL((url) =>
          url.href.startsWith(
            "https://www.dmm.co.jp/dc/-/viewer/=/product_id=",
          ),
        );

        imageFiles.push(...(await page.evaluate(getImageFiles)));
      } else {
        for (const link of Object.values(body.data.downloadLinks)) {
          const url = new URL(link, "https://www.dmm.co.jp/").href;
          imageFiles.push({ url });
        }
      }

      return imageFiles.map((imageFile) => async () => {
        const blob = await browser.drawImage(page, imageFile);

        process.stderr.write(".");

        return blob;
      });
    },
    loginEndpoints: ["https://accounts.dmm.co.jp/service/login/password"],
    loginSuccessUrl: (url: URL) => url.href === "https://www.dmm.co.jp/top/",
    logoutEndpoints: ["https://accounts.dmm.co.jp/service/logout"],
  };
}

FanzaDoujin.siteUrl = (url: URL) =>
  url.href.startsWith(
    "https://www.dmm.co.jp/dc/-/mylibrary/detail/=/product_id=",
  );