// Import QR generator
import QRCode from 'qrcode';

/*------------------------------------------------------------------------*/
/* ------------------------------ Constants ----------------------------- */
/*------------------------------------------------------------------------*/

/*----------------------------------------*/
/* ---------- Adjustable Params --------- */
/*----------------------------------------*/

// Width of generated image
const WIDTH_PX = 800;

// Card styling
const BACKGROUND_COLOR = '#A41034'; // Harvard Crimson
const WIDTH_TO_HEIGHT_RATIO = 1.2;
const CARD_BORDER_RADIUS_RATIO = 0.06;

// Text styling
const TEXT_COLOR = 'white';
const TEXT = 'Scan to Check In';
const TEXT_SIZE_RATIO = 0.11;
const TEXT_TO_TOP_BORDER_RATIO = 0.1;

// QR code styling
const CARD_TO_QR_CODE_WIDTH_RATIO = 0.85;
const QR_BORDER_RADIUS_RATIO = 0.04;

/*----------------------------------------*/
/* ---- Dynamically-generated Params ---- */
/*----------------------------------------*/

// Don't customize the look here, these are based on params above

// Canvas size
const canvasWidth = WIDTH_PX * window.devicePixelRatio;
const canvasHeight = canvasWidth * WIDTH_TO_HEIGHT_RATIO;

// Card size and location
const cardWidth = WIDTH_PX;
const cardHeight = WIDTH_TO_HEIGHT_RATIO * WIDTH_PX;
const cardRadius = CARD_BORDER_RADIUS_RATIO * WIDTH_PX;

// Text size and location
const textFontSize = TEXT_SIZE_RATIO * WIDTH_PX;
const textX = WIDTH_PX / 2;
const textY = TEXT_TO_TOP_BORDER_RATIO * WIDTH_PX;

// Sub-text size and location
const subTextFontSize = textFontSize / 1.6;
const subTextX = textX;
const subTextY = 2 * textY;

// QR code size and location
const qrWidth = WIDTH_PX * CARD_TO_QR_CODE_WIDTH_RATIO;
const qrX = WIDTH_PX * (1 - CARD_TO_QR_CODE_WIDTH_RATIO) / 2;
const qrY = (WIDTH_PX * WIDTH_TO_HEIGHT_RATIO) - qrX - (WIDTH_PX * CARD_TO_QR_CODE_WIDTH_RATIO) + (TEXT_TO_TOP_BORDER_RATIO * WIDTH_PX / 5.25);
const qrRadius = QR_BORDER_RADIUS_RATIO * WIDTH_PX;

/*------------------------------------------------------------------------*/
/* ---------------------------- QR Generator ---------------------------- */
/*------------------------------------------------------------------------*/

/**
 * Create a QR code card, with specified text, QR code value, and background color.
 * Could be made server-side via the node-canvas package
 * @author Benedikt Arnarsson
 * @author Gabe Abrams
 * @param value the URL which the QR code will hold
 * @returns the dataURL representing the QR card image
 */
const getQrCardImg = async (value: string, subText=''): Promise<string> => {
  // Create invisible canvas
  // Reference: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator
  const canvas = document.createElement('canvas');
  const context = canvas.getContext('2d')!;
  context.canvas.hidden = true;

  // Configure canvas size
  // See SO: https://stackoverflow.com/a/65124939
  canvas.width = canvasWidth;
  canvas.height = canvasHeight;
  context.scale(window.devicePixelRatio, window.devicePixelRatio);

  // Card background
  context.beginPath();
  context.fillStyle = BACKGROUND_COLOR;
  context.roundRect(
    0,
    0,
    cardWidth,
    cardHeight,
    cardRadius,
  );
  context.stroke();
  context.fill();

  // QR background
  context.beginPath();
  context.fillStyle = 'white';
  context.strokeStyle = 'white';
  context.roundRect(qrX, qrY, qrWidth, qrWidth, qrRadius);
  context.stroke();
  context.fill();

  // Text
  context.font = `bold ${textFontSize}px arial`;
  context.textAlign = 'center';
  context.textBaseline = 'middle';
  context.fillStyle = TEXT_COLOR;
  context.fillText(TEXT, textX, textY);

  // Sub-text
  const formattedSubText = (
    subText.length >= 15
      ? `${subText.substring(0, 15)}...`
      : subText
  );
  context.font = `bold ${subTextFontSize}px arial`;
  context.textAlign = 'center';
  context.textBaseline = 'middle';
  context.fillStyle = TEXT_COLOR;
  context.fillText(formattedSubText, subTextX, subTextY);

  // QR code
  // > Generate QR code image
  const qrCodeDataURL = await QRCode.toDataURL(
    value,
    {
      width: qrWidth,
      margin: 2,
      color: {
        light: '#ffffff00', // white, fully transparent
      },
    },
  );
  // > Convert to HTML Image
  const qrImg = new Image();
  qrImg.src = qrCodeDataURL;
  // > Wait for image to process/load
  await new Promise((resolve) => {
    qrImg.onload = resolve;
  });
  // > Draw image to canvas
  context.drawImage(qrImg, qrX, qrY, qrWidth, qrWidth);

  // Return data URL and destroy canvas
  const qrCard = canvas.toDataURL();
  canvas.remove();
  return qrCard;
};

export default getQrCardImg;
