const { Canvas, FontLibrary } = require("skia-canvas");
const Chart = require("chart.js/auto");

const { backgroundColors, borderColors } = require("./canvas-colors");
const { defaultsDeep, isNumber } = require("lodash");

const CANVAS_QUEUE_LIMIT = 100;

let isProcessing = false;
const requestQueue = [];

try {
  FontLibrary.use("Montserrat", [
    "/usr/share/fonts/Montserrat-Regular.ttf",
    "/usr/share/fonts/Montserrat-Bold.ttf",
    "/usr/share/fonts/Montserrat-Italic.ttf"
  ]);
} catch (error) {
  console.error(
    "Error loading fonts Skia Canvas Fonts, please be sure to install Montserrat font package",
    error.message
  );
}

// Utility to create a chart configuration
const getChartConfiguration = (keys, values, override) => {
  const defaultConfiguration = {
    type: "doughnut",
    data: {
      labels: keys,
      datasets: [
        {
          data: values,
          backgroundColor: backgroundColors,
          borderColor: borderColors,
          borderWidth: 1
        }
      ]
    },
    options: {
      devicePixelRatio: 4,
      responsive: false,
      animation: false,
      maintainAspectRatio: true,
      circumference: 180,
      rotation: -90,
      plugins: {
        legend: {
          labels: {
            boxWidth: 20,
            font: {
              family: "'Montserrat'",
              size: 10,
              style: "normal",
              weight: "normal"
            }
          },
          position: "left"
        }
      }
    }
  };

  return defaultsDeep(override || {}, defaultConfiguration);
};

const processCanvasRequest = async (req, res) => {
  const { logger } = req;
  const { w, h, values, keys, override } = req.body;

  logger.log("inbound-canvas-creation", "debug", "jsr", null, { w, h, values, keys, override });

  // Default width and height
  const width = isNumber(w) && w > 0 ? w : 500;
  const height = isNumber(h) && h > 0 ? h : 275;
  const configuration = getChartConfiguration(keys, values, override);

  let chart = null;

  try {
    const canvas = new Canvas(width, height);
    const ctx = canvas.getContext("2d");

    chart = new Chart(ctx, configuration);

    const chartImage = (await canvas.toBuffer("image/png")).toString("base64");
    res.status(200).send(`data:image/png;base64,${chartImage}`);
  } catch (error) {
    logger.log("canvas-error", "error", "jsr", null, { error: error.message });
    res.status(500).send("Error generating canvas");
  } finally {
    chart?.destroy();
  }
};

const enqueueRequest = (req, res) => {
  if (requestQueue.length >= CANVAS_QUEUE_LIMIT) {
    res.status(503).send("Server is busy. Please try again later.");
    return false;
  }
  requestQueue.push({ req, res });
  req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
  return true;
};

const processNextInQueue = async () => {
  try {
    while (requestQueue.length > 0) {
      const { req, res } = requestQueue.shift();
      try {
        await processCanvasRequest(req, res);
      } catch (err) {
        console.error("canvas-queue-error", "error", "jsr", null, { error: err.message });
      }
    }
  } finally {
    isProcessing = false;
  }
};

exports.canvastest = function (req, res) {
  res.status(200).send("OK");
};

exports.canvas = async (req, res) => {
  if (!enqueueRequest(req, res)) return;

  if (!isProcessing) {
    isProcessing = true;
    processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
  }
};
