const { rimraf, chalk } = require('@umijs/utils');
const path = require('path');
const zlib = require('zlib');
const fs = require('fs');
const WARN_AFTER_BUNDLE_GZIP_SIZE = 1.8 * 1024 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1 * 1024 * 1024;

function printFileSizes(stats, dir) {
  const ui = require('cliui')({ width: 120 });
  const json = stats.toJson({
    hash: false,
    modules: false,
    chunks: false,
  });

  const filesize = bytes => {
    bytes = Math.abs(bytes);
    const radix = 1024;
    const unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    let loop = 0;

    // calculate
    while (bytes >= radix) {
      bytes /= radix;
      ++loop;
    }
    return `${bytes.toFixed(1)} ${unit[loop]}`;
  };

  const assets = json.assets
    ? json.assets
    : json && json.children.reduce((acc, child) => acc.concat(child.assets), []);

  const seenNames = new Map();
  const isJS = val => /\.js$/.test(val);
  const isCSS = val => /\.css$/.test(val);

  const orderedAssets =
    assets &&
    assets
      .map(a => {
        a.name = a.name.split('?')[0];
        const isMainBundle = a.name.indexOf('main.') === 0;
        const maxRecommendedSize = isMainBundle
          ? WARN_AFTER_BUNDLE_GZIP_SIZE
          : WARN_AFTER_CHUNK_GZIP_SIZE;
        const isLarge = maxRecommendedSize && a.size > maxRecommendedSize;
        return {
          ...a,
          suggested: isLarge && isJS(a.name),
        };
      })
      .filter(a => {
        if (seenNames.has(a.name)) {
          return false;
        }
        seenNames.set(a.name, true);
        return isJS(a.name) || isCSS(a.name);
      })
      .sort((a, b) => {
        if (isJS(a.name) && isCSS(b.name)) return -1;
        if (isCSS(a.name) && isJS(b.name)) return 1;
        return b.size - a.size;
      });

  function getGzippedSize(asset) {
    const filepath = path.resolve(path.join(dir, asset.name));
    if (fs.existsSync(filepath)) {
      const buffer = fs.readFileSync(filepath);
      return filesize(zlib.gzipSync(buffer).length);
    }
    return filesize(0);
  }

  function makeRow(a, b, c) {
    return ` ${a}\t      ${b}\t ${c}`;
  }

  ui.div(
    makeRow(
      chalk.cyan.bold(`File`),
      chalk.cyan.bold(`Size`),
      chalk.cyan.bold(`Gzipped`),
    ) +
      `\n\n` +
      orderedAssets && orderedAssets .map(asset =>
          makeRow(
            /js$/.test(asset.name)
              ? asset.suggested
                ? 
                  chalk.yellow(path.join(dir, asset.name))
                : chalk.green(path.join(dir, asset.name))
              : chalk.blue(path.join(dir, asset.name)),
            filesize(asset.size),
            getGzippedSize(asset),
          ),
        )
        .join(`\n`),
  );

  console.log(
    `${ui.toString()}\n\n  ${chalk.gray(
      `Images and other types of assets omitted.`,
    )}\n`,
  );

  if (orderedAssets && orderedAssets.some((asset) => asset.suggested)) {
    // We'll warn for bundles exceeding them.
    console.log();
    console.log(
      chalk.yellow('The bundle size is significantly larger than recommended.'),
    );

    console.log(
      chalk.yellow(
        'You can also analyze the project dependencies using ANALYZE=1',
      ),
    );
    console.log();
  }
}

module.exports = {
    printFileSizes
}