import {
  PDFDocument,
  PDFPage,
  rgb,
} from "https://cdn.skypack.dev/pdf-lib@^1.11.1?dts";
import fontkit from "https://cdn.skypack.dev/@pdf-lib/fontkit@^1.0.0?dts";

type Result = {
  id: number;
  word: string;
  answer: string;
};

async function generateVoca(levels: number[], day: number) {
  const re =
    /<p class="word">(?<id>\d+?)\. (?<word>.+?)<\/p>.*?<span class="af_answer">(?<answer>.+?)<\/span>/gis;
  const res = await fetch(
    `https://www.hackers.co.kr/?c=s_toeic/new_voca_toeic_testpaper/toeic_study/new_paper&mode=new_view&level=${
      levels.join(",")
    }&level_type=&lang_text=2&question=1000&day3=${day}&day4=${day}&day_auto=N&index=1`,
  );

  const body = await res.text();
  const matches = [...body.matchAll(re)].map((m) => ({
    ...(m.groups as unknown as Result),
    id: Number.parseInt(m.groups?.id as string),
  }));

  const pdfDoc = await PDFDocument.create();

  const fontBytes = await Deno.readFile("./NanumGothic.ttf");
  pdfDoc.registerFontkit(fontkit);
  const customFont = await pdfDoc.embedFont(fontBytes);

  const fontSize = 12;
  const margin = 20;
  const perColumn = 25;
  const perPage = 50;

  let page!: PDFPage;
  let col = -1;
  let yCursor = 1;

  // 문제 생성
  for (let i = 0; i < matches.length; ++i) {
    const data = matches[i];
    if (i % perPage === 0) {
      page = pdfDoc.addPage();
      yCursor = 1;
      col = -1;
    }
    if (i % perColumn === 0) {
      col++;
      yCursor = 1;
    }
    page.drawText(`${data.id}. ${data.word}`, {
      x: margin + (page.getWidth() / 2) * col,
      y: page.getHeight() - (fontSize + margin) * yCursor,
      size: fontSize,
      font: customFont,
      color: rgb(0, 0, 0),
    });
    page.drawText("_________________", {
      x: margin + (page.getWidth() / 2) * col + 140,
      y: page.getHeight() - (fontSize + margin) * yCursor - 3,
      size: fontSize,
      font: customFont,
      color: rgb(0, 0, 0),
    });
    yCursor++;
  }

  // 답 생성
  for (let i = 0; i < matches.length; ++i) {
    const data = matches[i];
    if (i % perPage === 0) {
      page = pdfDoc.addPage();
      yCursor = 1;
      col = -1;
    }
    if (i % perColumn === 0) {
      col++;
      yCursor = 1;
    }
    page.drawText(`${data.id}. ${data.word}`, {
      x: margin + (page.getWidth() / 2) * col,
      y: page.getHeight() - (fontSize + margin) * yCursor,
      size: fontSize,
      font: customFont,
      color: rgb(0, 0, 0),
    });
    page.drawText("_________________", {
      x: margin + (page.getWidth() / 2) * col + 140,
      y: page.getHeight() - (fontSize + margin) * yCursor - 3,
      size: fontSize,
      font: customFont,
      color: rgb(0, 0, 0),
    });
    page.drawText(data.answer, {
      x: margin + (page.getWidth() / 2) * col + 140,
      y: page.getHeight() - (fontSize + margin) * yCursor,
      size: 8,
      font: customFont,
      color: rgb(1, 0, 0),
    });
    yCursor++;
  }

  const pdfBytes = await pdfDoc.save();
  return pdfBytes;
}

const port = 8055;
const server = Deno.listen({ port });
console.log(
  `HTTP webserver running.  Access it at:  http://localhost:${port}/`,
);

for await (const conn of server) {
  serveHttp(conn);
}

async function serveHttp(conn: Deno.Conn) {
  const httpConn = Deno.serveHttp(conn);
  for await (const requestEvent of httpConn) {
    const { searchParams, pathname } = new URL(requestEvent.request.url);

    if (pathname.startsWith("/generate")) {
      if (!searchParams.has("level") || !searchParams.has("day")) {
        requestEvent.respondWith(
          new Response("Not Found", {
            status: 404,
          }),
        );
        continue;
      }

      const levels = searchParams.getAll("level").map((l) =>
        Number.parseInt(l)
      );
      const day = Number.parseInt(searchParams.get("day")!) ?? 1;
      const data = await generateVoca(levels, day);

      requestEvent.respondWith(
        new Response(data, {
          status: 200,
          headers: {
            "Content-Disposition": 'attachment; filename="voca.pdf"',
          },
        }),
      );
    } else if (pathname.startsWith("/") || pathname.startsWith("/index.html")) {
      const file = await Deno.readFile("./index.html");
      requestEvent.respondWith(
        new Response(file, {
          headers: {
            "content-type": "text/html",
          },
        }),
      );
    }
  }
}
