import { fabric } from "fabric";
import {
  clearObjects,
  sortObjects,
  transformHighlightedText,
  checkTextBoxHeight,
} from "../../components/canvas/utils";
import { PaddedHighlightingTextbox } from "../../components/canvas/textbox";

import tearImageURL from "../../assets/template/newspaper_quote/newspaper_tear_top.png";
import quoteImageURL from "../../assets/template/newspaper_quote/quote.svg";

let mainTextBox = null;
let mainTextBoxBackground = null;

let personNameText = null;
let personInfoSeparator = null;
let personPositionText = null;
let sourceText = null;

let contractedByTextbox = null;

let mainImage = null;
let logoImage = null;
let quoteImage = null;
let tearImage = null;
let sourceImage = null;

let leftQuote = null;
let rightQuote = null;

let tear = null;
let tearFill = null;

let mainImageSource = null;
let previousLogoPosition = null;

const redraw = async (canvas, options) => {
  clearObjects(
    [
      mainTextBox,
      mainTextBoxBackground,
      personInfoSeparator,
      personNameText,
      personPositionText,
      contractedByTextbox,
      leftQuote,
      rightQuote,
      tear,
      tearFill,
    ],
    canvas,
  );

  canvas.preserveObjectStacking = true;

  const textMarginSides = Math.ceil(canvas.width * 0.11);
  let mainTextMarginBottom = Math.ceil(canvas.height * 0.07);
  const mainTextSize = Math.ceil(canvas.height * 0.043);
  const mainTextLineHeight = 1.3;

  const nameTextMarginTop = Math.ceil(canvas.height * 0.025);
  const positionTextSideGap = Math.ceil(canvas.width * 0.01);
  const positionTextSeparatorWidth = Math.ceil(canvas.width * 0.0035);
  const personInfoTextMaxWidth = Math.ceil(canvas.width * 0.5);

  const bottomTextSize = Math.ceil(canvas.height * 0.03);
  const additionalContentExtraBottomMargin = Math.ceil(canvas.height * 0.1);

  const contractedByTextSize = Math.ceil(canvas.height * 0.02);
  const contractedByTextMaxWidth = Math.ceil(canvas.width * 0.9);
  const contractedByTextSidesMargin = Math.ceil(canvas.width * 0.03);

  const logoWidth = Math.ceil(canvas.width * 0.2);
  const logoSideMargin = Math.ceil(canvas.width * 0.07);

  const sourceImageHeight = Math.ceil(canvas.height * 0.07);
  const sourceImageMarginBottom = Math.ceil(canvas.width * 0.075);
  const sourceImageMarginSide = Math.ceil(canvas.width * 0.07);

  const sourceTextMarginSide = Math.ceil(canvas.width * 0.005);

  const quoteHeight = Math.ceil(canvas.height * 0.042);

  const leftQuoteMarginSide = Math.ceil(canvas.width * 0.065);
  const leftQuoteMarginSideExtra = Math.ceil(canvas.width * -0.005);
  const leftQuoteMarginTop = 0;

  const rightQuoteMarginSide = Math.ceil(canvas.width * 0.0175);
  const rightQuoteMarginSideExtra = Math.ceil(canvas.width * 0.005);
  const rightQuoteMarginTop = 0;

  const tearMarginBottom = Math.ceil(canvas.height * 0.15);

  if (options.mainText !== null) {
    /* BEGIN Name text render */

    if (options.personName !== null) {
      mainTextMarginBottom += additionalContentExtraBottomMargin;

      personNameText = new fabric.Text(options.personName, {
        left: textMarginSides,
        top: canvas.height - mainTextMarginBottom + nameTextMarginTop,
        fontFamily: "Roboto Condensed",
        fontSize: bottomTextSize,
        fontWeight: "bold",
        fill: options.colors.baseText.value,
        selectable: false,
        zIndex: 10,
      });

      canvas.add(personNameText);

      if (options.personPosition !== null) {
        personInfoSeparator = new fabric.Rect({
          left:
            personNameText.left + personNameText.width + positionTextSideGap,
          top: personNameText.top,
          width: positionTextSeparatorWidth,
          fill: options.colors.baseText.value,
          selectable: false,
          zIndex: 10,
        });

        canvas.add(personInfoSeparator);

        personPositionText = new fabric.Textbox(options.personPosition, {
          left:
            personInfoSeparator.left +
            personInfoSeparator.width +
            positionTextSideGap,
          top: personNameText.top,
          width: personInfoTextMaxWidth - personNameText.width,
          fontFamily: "Roboto Condensed",
          fontSize: bottomTextSize,
          fill: options.colors.baseText.value,
          selectable: false,
          zIndex: 10,
        });

        checkTextBoxHeight(personPositionText, 2);

        canvas.add(personPositionText);
        personInfoSeparator.set({ height: personPositionText.height });
        canvas.renderAll();
      }
    }

    /* END Name text render */

    /* BEGIN Source image render */

    const createNewSourceImage =
      options.sourceImage !== null &&
      (sourceImage === null ||
        (options.sourceImage !== null &&
          options.sourceImage !== sourceImage._element));

    if (options.sourceImage !== null && options.personName === null) {
      mainTextMarginBottom += additionalContentExtraBottomMargin;
    }

    if (createNewSourceImage) {
      canvas.remove(sourceImage);
      canvas.remove(sourceText);

      sourceImage = new fabric.Image(options.sourceImage, {});
      sourceImage.scaleToHeight(sourceImageHeight);
      sourceImage.set({
        left:
          canvas.width - sourceImage.getScaledWidth() - sourceImageMarginSide,
        top: canvas.height - sourceImageHeight - sourceImageMarginBottom,
        selectable: false,
        zIndex: 10,
      });

      canvas.add(sourceImage);

      sourceText = new fabric.Text("Zdroj: ", {
        fontSize: bottomTextSize,
        fill: options.colors.baseText.value,
        fontFamily: "Roboto Condensed",
        left: sourceImage.left - sourceTextMarginSide,
        top: sourceImage.top,
        selectable: false,
        zIndex: 10,
      });

      sourceText.set({
        left: sourceText.left - sourceText.width,
      });

      canvas.add(sourceText);
    } else if (options.sourceImage === null) {
      canvas.remove(sourceImage);
      canvas.remove(sourceText);
    }

    /* END Source image render */

    /* BEGIN Main text render */

    const mainTextWidth = canvas.width - textMarginSides * 2;

    const highlightedData = transformHighlightedText(
      options.mainText,
      mainTextSize,
      mainTextWidth,
      "Glegoo",
      options.colors.highlight.value,
      options.colors.highlightedText.value,
      { padWhenDiacritics: true },
    );

    mainTextBox = new PaddedHighlightingTextbox(highlightedData.text, {
      width: canvas.width,
      left: textMarginSides,
      textAlign: "left",
      fontFamily: "Glegoo",
      fontStyle: "bold",
      fontSize: mainTextSize,
      lineHeight: mainTextLineHeight,
      fill: options.colors.baseText.value,
      styles: highlightedData.styles,
      selectable: false,
      highlightPadding: canvas.height * 0.008,
      zIndex: 10,
    });

    checkTextBoxHeight(mainTextBox, 4);

    canvas.add(mainTextBox);

    const mainTextBoxTop =
      canvas.height - mainTextBox.height - mainTextMarginBottom;

    mainTextBox.top = mainTextBoxTop - highlightedData.paddingBottom;

    canvas.renderAll();

    /* END Main text render */

    /* BEGIN Left quote render */

    // Load on first render
    if (quoteImage === null) {
      quoteImage = new Image();

      const quoteImageLoadPromise = new Promise((resolve) => {
        quoteImage.onload = () => {
          resolve();
        };
      });

      quoteImage.src = quoteImageURL;

      await quoteImageLoadPromise;
    }

    leftQuote = new fabric.Image(quoteImage, {
      selectable: false,
      zIndex: 10,
    });
    leftQuote.scaleToHeight(quoteHeight);
    leftQuote.set({
      left:
        leftQuoteMarginSide +
        (options.mainText[0] === "*" ? leftQuoteMarginSideExtra : 0),
      top: mainTextBoxTop + leftQuoteMarginTop,
    });

    canvas.add(leftQuote);

    /* END Left quote render */

    /* BEGIN Right quote render */

    rightQuote = new fabric.Image(quoteImage, {
      flipX: true,
      selectable: false,
      zIndex: 10,
    });
    rightQuote.scaleToHeight(quoteHeight);
    rightQuote.set({
      left:
        mainTextBox.left +
        mainTextBox.__lineWidths[mainTextBox.__lineWidths.length - 1] +
        rightQuoteMarginSide +
        (options.mainText[options.mainText.length - 1] === "*"
          ? rightQuoteMarginSideExtra
          : 0),
      top:
        mainTextBoxTop +
        mainTextBox.__lineHeights
          .slice(0, -1)
          .reduce((partialSum, a) => partialSum + a, 0) +
        rightQuoteMarginTop,
    });

    canvas.add(rightQuote);

    /* END Right quote render */

    /* BEGIN Tear render */

    // Load on first render
    if (tearImage === null) {
      tearImage = new Image();

      const tearImageLoadPromise = new Promise((resolve) => {
        tearImage.onload = () => {
          resolve();
        };
      });

      tearImage.src = tearImageURL;

      await tearImageLoadPromise;
    }

    tear = new fabric.Image(tearImage, {
      selectable: false,
      zIndex: 11,
    });
    tear.scaleToWidth(canvas.width);
    tear.set({
      top: mainTextBoxTop - tearMarginBottom,
      left: 0,
    });

    canvas.add(tear);

    /* END Tear render */

    /* BEGIN Tear fill render */

    tearFill = new fabric.Polygon(
      [
        { x: -canvas.width * 0.01, y: tear.top + canvas.height * 0.05 },
        // Hacky seam fix
        { x: canvas.width * 0.1, y: tear.top + canvas.height * 0.025 },
        { x: canvas.width * 0.15, y: tear.top + canvas.height * 0.02 },
        { x: canvas.width * 0.2, y: tear.top + canvas.height * 0.033 },
        { x: canvas.width * 0.3, y: tear.top + canvas.height * 0.065 },
        { x: canvas.width * 0.4, y: tear.top + canvas.height * 0.06 },
        { x: canvas.width * 0.5, y: tear.top + canvas.height * 0.07 },
        { x: canvas.width * 0.53, y: tear.top + canvas.height * 0.065 },
        { x: canvas.width * 0.6, y: tear.top + canvas.height * 0.08 },
        { x: canvas.width * 0.75, y: tear.top + canvas.height * 0.05 },
        { x: canvas.width * 0.85, y: tear.top + canvas.height * 0.08 },
        { x: canvas.width, y: tear.top + canvas.height * 0.12 },
        { x: canvas.width, y: tear.top },
        { x: canvas.width, y: mainTextBoxTop },
        { x: -canvas.width * 0.01, y: mainTextBoxTop },
        // Hacky seam fix
      ],
      {
        top: tear.top + canvas.height * 0.005, // Hacky seam fix
        left: -(canvas.width * 0.005),
        fill: options.colors.background.value,
        selectable: false,
        zIndex: 9,
      },
    );

    canvas.add(tearFill);

    /* END Tear fill render */

    /* BEGIN Main text background render */

    const backgroundHeight = canvas.height - mainTextBoxTop;

    mainTextBoxBackground = new fabric.Rect({
      width: canvas.width * 1.01,
      height: backgroundHeight,
      left: -(canvas.width * 0.005),
      top: mainTextBoxTop,
      fill: options.colors.background.value,
      selectable: false,
      zIndex: 9,
    });

    canvas.add(mainTextBoxBackground);

    /* END Main text background render */
  }

  /* BEGIN Main image render */

  if (
    options.mainImage !== null &&
    (!canvas.contains(mainImage) ||
      mainImage === null ||
      options.mainImage.src !== mainImageSource)
  ) {
    if (mainImage !== null) {
      canvas.remove(mainImage);
    }

    mainImage = new fabric.Image(options.mainImage, {
      left: 0,
      top: 0,
      zIndex: 0,
    });

    mainImage.controls = {
      ...fabric.Image.prototype.controls,
      mtr: new fabric.Control({ visible: false }),
    };

    if (mainImage.width >= mainImage.height) {
      mainImage.scaleToHeight(canvas.height);
    } else {
      mainImage.scaleToWidth(canvas.width);
    }

    canvas.add(mainImage);
    mainImageSource = options.mainImage.src;
    // canvas.centerObject(mainImage)
  } else if (mainImage !== null && options.mainImage === null) {
    canvas.remove(mainImage);
  }

  /* END Main image render */

  /* BEGIN Logo render */

  // A logo is provided, and it either hasn't been rendered yet or is a new one.
  const createNewLogo =
    (options.logoImage !== null &&
      (logoImage === null ||
        (options.logoImage !== null &&
          options.logoImage !== logoImage._element))) ||
    previousLogoPosition != options.logoPosition.id;

  previousLogoPosition = options.logoPosition.id;

  if (createNewLogo) {
    canvas.remove(logoImage);

    logoImage = new fabric.Image(options.logoImage, { selectable: false });
    logoImage.scaleToWidth(logoWidth);

    if (options.logoPosition.id == "top-right") {
      logoImage.set({
        left: canvas.width - logoWidth - logoSideMargin,
        top: logoSideMargin,
        zIndex: 11,
      });
    } else {
      logoImage.set({
        left: logoSideMargin,
        top: logoSideMargin,
        zIndex: 11,
      });
    }

    canvas.add(logoImage);
  }

  /* END Logo render */

  /* BEGIN Contracted by render */

  if (options.contractedBy !== null) {
    contractedByTextbox = new fabric.Textbox(options.contractedBy, {
      left:
        canvas.width - contractedByTextMaxWidth - contractedByTextSidesMargin,
      top: canvas.height - contractedByTextSidesMargin - contractedByTextSize,
      width: contractedByTextMaxWidth,
      fontFamily: "Roboto Condensed",
      fontSize: contractedByTextSize,
      textAlign: "right",
      fill: options.colors.contractedByText.value,
      selectable: false,
      zIndex: 10,
    });

    checkTextBoxHeight(contractedByTextbox, 1);

    canvas.add(contractedByTextbox);
  }

  /* END Contracted by render */

  sortObjects(canvas);
};

export default redraw;
