const { build } = require('@kasko/webapp-flow-visualizer-lib');
const fs = require('fs');
const { createSpinner } = require('nanospinner');

const getItem = require('./getItem');
const getSubProduct = require('./getSubProduct');
const getWebappData = require('./getWebappData');

/**
 * @typedef {Object} Flags
 * @property {("png" | "pdf" | "svg")=} format
 * @property {number=} fontSize
 * @property {boolean=} silent
 * @property {("json" | "verbose")=} output
 * @property {boolean=} fromCli
 * @property {boolean=} file
 */

/**
 * @param {Flags} flags
 * @param {string[]} attributes
 * @returns {Promise<Buffer[]>}
 */
async function graph(
  // rome-ignore lint/style/useDefaultParameterLast: <explanation>
  {
    format = 'png',
    fontSize = undefined,
    silent = false,
    output = 'verbose',
    fromCli = false,
    file = false,
  } = {},
  attributes,
) {
  let nodeCanvas;
  try {
    // @ts-ignore
    nodeCanvas = require('canvas');
  } catch (e) {
    throw new Error('Install "canvas" package to use `graph` command!');
  }

  const showVerboseOutput = output !== 'verbose' || !fromCli || silent;

  /**
   * @param {string} text
   * @returns {import('nanospinner').Spinner}
   */
  function spin(text) {
    if (showVerboseOutput) {
      /** @type {*} */
      const mock = {
        success: () => {},
        error: () => {},
        text: null,
      };

      return mock;
    }

    return createSpinner(text).start();
  }

  /** @type {import('nanospinner').Spinner} */
  let spinner;

  spinner = spin(`Loading webapp configuration ${attributes.length}`);

  const response = await Promise.all(attributes.map(getWebappData));

  spinner.success();

  spinner = spin(
    `Loading webapp items ${response.reduce(
      (acc, webapp) => acc + webapp.touchpointData.items.length,
      0,
    )}`,
  );

  const responseItems = await Promise.all(
    response
      .map((webapp) =>
        webapp.touchpointData.items.map((item) => {
          if (/^ins_/.test(item.id)) {
            return getSubProduct(webapp.kaskoConfig, item).then((itemData) => ({
              ...webapp,
              itemData,
            }));
          }

          return getItem(webapp.kaskoConfig, item).then((itemData) => ({
            ...webapp,
            itemData,
          }));
        }),
      )
      .flat(2),
  );

  spinner.success();

  const results = [];
  for (const webapp of responseItems) {
    spinner = spin(`Generating flow graph "${webapp.itemData.id}"`);

    const canvas = nodeCanvas.createCanvas(0, 0, format === 'png' ? undefined : format);
    const data = build(
      canvas,
      webapp.touchpointData.manifest,
      webapp.itemData.manifest,
      webapp.itemData.fields,
      undefined,
      undefined,
      {
        fontSize,
      },
    ).toBuffer();
    results.push(data);

    spinner.success();

    if (output === 'json' && fromCli) {
      // Print method won't work here, as it adds unnecessary characters
      process.stdout.write(`${JSON.stringify(responseItems)}\n`);
    }

    if (file) {
      const fileName = `${webapp.touchpointData.id}-${webapp.itemData.id}.${format}`;
      spinner = spin(`Creating file "${fileName}"`);
      fs.writeFileSync(fileName, data);
      spinner.success();
    }
  }

  return Promise.resolve(results);
}

module.exports = graph;
module.exports.readme = require('./readme.md');
