import React from "react";
import styled from "styled-components";
import useDimensions from "react-cool-dimensions";
import Debug from "debug";
import { BugButtonSubmissionContainer, ImageSize } from "./BugButtonApp";
const debug = Debug("userbugreport:PageCapture");

/**
 * Capture the screen to a canvas, this is the complete screen
 * currently in view.
 */
export const capture = async (): Promise<HTMLCanvasElement> => {
  debug("capturing", window.devicePixelRatio);
  // yeah I know this is funky -- it's to get the SSR build
  // working with Docusaurus that has a 'window is not defined' problem
  // if this is used as an import above
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const html2canvas = require("html2canvas");
  const canvas = (await html2canvas(document.body, {
    x: 0,
    y: 0,
    scrollX: window.scrollX,
    scrollY: window.scrollY,
    windowWidth: window.outerWidth,
    windowHeight: window.outerHeight,
    scale: 1,
    useCORS: true,
  })) as HTMLCanvasElement;
  debug("captured", canvas);
  // that's the inital capture -- now crop out the active viewport
  const croppedCanvas = document.createElement("canvas");
  croppedCanvas.width = window.visualViewport.width;
  croppedCanvas.height = window.visualViewport.height;
  const ctx = croppedCanvas.getContext("2d");
  ctx.drawImage(
    canvas,
    window.visualViewport.pageLeft,
    window.visualViewport.pageTop,
    window.visualViewport.width,
    window.visualViewport.height,
    0,
    0,
    window.visualViewport.width,
    window.visualViewport.height
  );
  debug("cropped", croppedCanvas, window.visualViewport);
  return croppedCanvas;
};

/**
 * Centering display control for the image.
 */
const Root = styled.div`
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
`;

/**
 * Configure the page capture with these.
 */
interface PageCaptureProps {
  /**
   * Style pass through to the form.
   */
  style?: React.CSSProperties;
  /**
   * Auto capture -- this is really just for testing.
   */
  autoCapture?: boolean;
  /**
   * tell the container the size
   */
  onResizeScreenshotToFit: (size: ImageSize) => void;
}

/**
 * PageCapture take the current page, and creates a complete copy
 * of it to work with as a kind of virtual screen-shot.
 */
export const PageCapture: React.FC<PageCaptureProps> = (
  props: PageCaptureProps
) => {
  debug("render", props);
  // dimensions -- used to scale
  const { ref, width, height } = useDimensions();
  // final output state -- share up
  const {
    setRawScreenshot,
    rawScreenshot,
  } = BugButtonSubmissionContainer.useContainer();

  React.useEffect(() => {
    const doit = async () => {
      debug("auto capture");
      setRawScreenshot(await capture());
    };
    props.autoCapture && doit();
  }, [props.autoCapture]);

  /**
   * Host the raw screenshot inside this element. This is a
   * bit of a ... high speed fusion of React and old school DOM-ery.
   */
  React.useEffect(() => {
    if (ref.current && rawScreenshot && width && height) {
      debug("display");
      // fill up the container, let the browser do the scaling work
      rawScreenshot.style.width = "";
      rawScreenshot.style.height = "";
      rawScreenshot.style.maxWidth = `${width}px`;
      rawScreenshot.style.maxHeight = `${height}px`;
      ref.current.appendChild(rawScreenshot);
      const observeSizedScreenshot = new window.ResizeObserver((entries) => {
        debug("resized", entries);
        if (entries.length) {
          const size = {
            width: entries[0].contentRect.width,
            height: entries[0].contentRect.height,
          };
          props.onResizeScreenshotToFit && props.onResizeScreenshotToFit(size);
        }
      });
      observeSizedScreenshot.observe(rawScreenshot);
      // cleaner upper
      return () => {
        observeSizedScreenshot.unobserve(rawScreenshot);
        ref.current.removeChild(rawScreenshot);
      };
    }
  }, [ref, rawScreenshot, width, height]);

  /**
   * Display the captured page screenshot scaled to fit.
   *
   * Canvas needs to be explicitly set to width and height. % or flex
   * makes it stretch, re-render - and always ends up siwht blocky pixel poor images.
   */
  return <Root style={props.style} ref={ref}></Root>;
};
