<template>
  <div>
    <button :disabled="!userSignatureZones" @click="confirm_sign">
      Confirmer la signature
    </button>
    <button :disabled="!userSignatureZones" @click="undo_sign">
      Supprimer la signature
    </button>
  </div>
  <div v-if="pageCount > 1">
    <button :disabled="page <= 1" @click="turn_page(-1)">❮</button>
    {{ page }} / {{ pageCount }}
    <button :disabled="page >= pageCount" @click="turn_page(1)">❯</button>
  </div>
  <canvas id="canvas"></canvas>
</template>

<script setup lang="ts">
import { ref, Ref } from "vue";
import { Signature, SignatureZone } from "../../types";
import * as pdfjsLib from "pdfjs-dist";
import {
  PDFDocumentProxy,
  PDFPageProxy,
} from "pdfjs-dist/types/src/display/api";

// @ts-ignore
import * as PdfWorker from "pdfjs-dist/build/pdf.worker.mjs";
console.log(PdfWorker); // incredible but this is needed

// import { PdfWorker } from 'pdfjs-dist/build/pdf.worker.mjs'
// pdfjsLib.GlobalWorkerOptions.workerSrc = PdfWorker;

import {
  build_download_info_link,
  download_and_decrypt_doc,
} from "../StoredObjectButton/helpers";

pdfjsLib.GlobalWorkerOptions.workerSrc = "pdfjs-dist/build/pdf.worker.mjs";

const page: Ref<number> = ref(1);
const pageCount: Ref<number> = ref(0);
let userSignatureZones: Ref<null | SignatureZone> = ref(null);
let pdfSource: Ref<string> = ref("");
let pdf = {} as PDFDocumentProxy;

declare global {
  interface Window {
    signature: Signature;
  }
}

const signature = window.signature;
const urlInfo = build_download_info_link(signature.storedObject.filename);

const mount_pdf = async (url: string) => {
  const loadingTask = pdfjsLib.getDocument(url);
  pdf = await loadingTask.promise;
  pageCount.value = pdf.numPages;
  await set_page(1);
};

const get_render_context = (pdfPage: PDFPageProxy) => {
  const scale = 1;
  const viewport = pdfPage.getViewport({ scale });
  const canvas = document.querySelectorAll("canvas")[0] as HTMLCanvasElement;
  const context = canvas.getContext("2d") as CanvasRenderingContext2D;
  canvas.height = viewport.height;
  canvas.width = viewport.width;

  return {
    canvasContext: context,
    viewport: viewport,
  };
};

const set_page = async (page: number) => {
  const pdfPage = await pdf.getPage(page);
  const renderContext = get_render_context(pdfPage);
  await pdfPage.render(renderContext);
};

async function download_and_open(): Promise<Blob> {
  let raw;
  try {
    raw = await download_and_decrypt_doc(
      urlInfo,
      signature.storedObject.keyInfos,
      new Uint8Array(signature.storedObject.iv)
    );
  } catch (e) {
    console.error("error while downloading and decrypting document", e);
    throw e;
  }
  await mount_pdf(URL.createObjectURL(raw));
  init_pdf();
  return raw;
}

const init_pdf = () => {
  const canvas = document.querySelectorAll("canvas")[0] as HTMLCanvasElement;
  canvas.addEventListener(
    "pointerup",
    (e: PointerEvent) => canvas_click(e, canvas),
    false
  );
  setTimeout(() => add_zones(page.value), 800);
};

const hit_signature = (
  zone: SignatureZone,
  xy: number[],
  canvasWidth: number,
  canvasHeight: number
) => {
  const scaleXToCanvas = (x: number) => (x * canvasWidth) / zone.pageWidth;
  const scaleYToCanvas = (y: number) => (y * canvasHeight) / zone.pageHeight;
  return (
    scaleXToCanvas(zone.x) < xy[0] &&
    xy[0] < scaleXToCanvas(zone.x + zone.width) &&
    scaleYToCanvas(zone.y) < xy[1] &&
    xy[1] < scaleYToCanvas(zone.y + zone.height)
  );
};

const canvas_click = (e: PointerEvent, canvas: HTMLCanvasElement) =>
  signature.zones
    .filter((z) => z.page === page.value)
    .map((z) => {
      if (
        hit_signature(z, [e.offsetX, e.offsetY], canvas.width, canvas.height)
      ) {
        const ctx = canvas.getContext("2d");
        if (ctx) {
          draw_zone(z, ctx, canvas.width, canvas.height, true);
        }
        userSignatureZones.value = z;
      }
    });

const turn_page = async (upOrDown: number) => {
  userSignatureZones.value = null;
  page.value = page.value + upOrDown;
  await set_page(page.value);
  setTimeout(() => add_zones(page.value), 200);
};

const draw_zone = (
  zone: SignatureZone,
  ctx: CanvasRenderingContext2D,
  canvasWidth: number,
  canvasHeight: number,
  selected = false,
) => {
  const scaleXToCanvas = (x: number) =>
    Math.round((x * canvasWidth) / zone.pageWidth);
  const scaleYToCanvas = (y: number) =>
    Math.round((y * canvasHeight) / zone.pageHeight);
  ctx.strokeStyle = selected ? "orange " : "yellow";
  ctx.lineWidth = 10;
  ctx.lineJoin = "bevel";
  ctx.strokeRect(
    scaleXToCanvas(zone.x),
    scaleYToCanvas(zone.y),
    scaleXToCanvas(zone.width),
    scaleYToCanvas(zone.height)
  );
};

const add_zones = (page: number) => {
  const canvas = document.querySelectorAll("canvas")[0];
  const ctx = canvas.getContext("2d");
  if (ctx) {
    signature.zones
      .filter((z) => z.page === page)
      .map((z) => draw_zone(z, ctx, canvas.width, canvas.height));
  }
};

const confirm_sign = () => {
  console.log(userSignatureZones.value);
  //TODO POST userSignatureZones to backend
};

const undo_sign = async () => {
  const canvas = document.querySelectorAll("canvas")[0];
  const ctx = canvas.getContext("2d");
  if (ctx && userSignatureZones.value) {
    draw_zone(userSignatureZones.value, ctx, canvas.width, canvas.height);
    //another option is to reload the canvas
    //await set_page(page.value);
    //setTimeout(() => add_zones(page.value), 200);
  }
  userSignatureZones.value = null;
};

download_and_open();
</script>

<style lang="scss">
</style>

