import { basename, resolve } from 'path';
import { writeFileSync, readFileSync } from 'fs';
import chalk from 'chalk';
import { ITiddlerFields } from 'tw5-typed';
import { minify as htmlMinify } from 'html-minifier-terser';
import { rebuild } from './packup';
import { tiddlywiki, mkdirsForFileSync, waitForFile } from './utils';

const printPlugins = (plugins: Map<string, string>) => {
  // eslint-disable-next-line no-console
  console.log(chalk.bgCyan.black.bold(' Minimized plugins '));
  plugins.forEach((plugin, title) => {
    let size = plugin.length;
    let unit = 'B  ';
    if (size > 1024) {
      size /= 1024;
      unit = 'KiB';
    }
    if (size > 1024) {
      size /= 1024;
      unit = 'MiB';
    }
    const sizeFormatted = `${size.toFixed(2)} ${unit}`.padStart(11);
    // eslint-disable-next-line no-console
    console.log(chalk.cyan(`${sizeFormatted}   ${title}`));
  });
  // eslint-disable-next-line no-console
  console.log('');
};

/**
 * 构建插件
 *
 * @async
 * @param {string} [output] 插件输出的路径，不填则只构建但不保存
 * @param {string} [excludeFilter] 排除构建的插件
 * @param {string} [srcPath='src'] 插件工程根路径
 * @return {Promise<ITiddlerFields[]>} 构建好的插件
 */
export const build = async (
  output?: string,
  excludeFilter?: string,
  srcPath = 'src',
) => {
  const $tw = tiddlywiki();
  const plugins = await rebuild($tw, srcPath, undefined, false, excludeFilter);
  const pluginJsons = new Map<string, string>();
  plugins.forEach(plugin => {
    const pluginTiddlerName = `${basename(
      $tw.utils.generateTiddlerFilepath(plugin.title, {}),
    )}.json`;
    const jsonStr = JSON.stringify(plugin);
    pluginJsons.set(plugin.title, jsonStr);
    if (output) {
      const path = resolve(output, pluginTiddlerName);
      mkdirsForFileSync(path);
      writeFileSync(path, jsonStr);
    }
  });
  printPlugins(pluginJsons);
  return plugins;
};

/**
 * 构建插件库
 *
 * @async
 * @param {string} output 插件库输出的路径
 * @param {string} [excludeFilter] 排除构建的插件
 * @param {string} [srcPath='src'] 插件工程根路径
 * @param {string} [wikiPath='wiki'] wiki 路径
 * @return {Promise<ITiddlerFields[]>} 构建好的插件
 */
export const buildLibrary = async (
  output: string,
  excludeFilter?: string,
  srcPath = 'src',
  wikiPath = 'wiki',
) => {
  const $tw = tiddlywiki();
  const plugins: Record<string, ITiddlerFields> = {};
  const pluginJsons = new Map<string, string>();
  (await rebuild($tw, srcPath, undefined, false, excludeFilter)).forEach(
    plugin => {
      const jsonStr = JSON.stringify(plugin);
      pluginJsons.set(plugin.title, jsonStr);
      plugins[plugin.title] = plugin;
    },
  );
  printPlugins(pluginJsons);
  const pluginPaths = $tw.getLibraryItemSearchPaths($tw.config.pluginsPath);
  // eslint-disable-next-line no-console
  console.log(chalk.green.bold('Generating plugin library...'));
  tiddlywiki(
    [
      /* 收集所有已安装插件 */
      {
        title: '$:/UpgradeLibrary',
        type: 'application/json',
        'plugin-type': 'library',
        text: JSON.stringify({ tiddlers: plugins }),
      },
      ...[
        'tiddlywiki/filesystem',
        'tiddlywiki/tiddlyweb',
        'tiddlywiki/pluginlibrary',
      ].map(
        pluginName =>
          $tw.loadPluginFolder(
            $tw.findLibraryItem(pluginName, pluginPaths as any)!,
          )!,
      ),
    ],
    wikiPath,
    [
      ...['--output', resolve(output)] /* 指定输出路径 */,
      ...[
        '--savelibrarytiddlers',
        '$:/UpgradeLibrary',
        '',
        'recipes/library/tiddlers/',
        '$:/UpgradeLibrary/List',
      ] /* 导出指定的插件 */,
      ...[
        '--savetiddler',
        '$:/UpgradeLibrary/List',
        'recipes/library/tiddlers.json',
      ] /* 生成插件集合JSON文件 */,
      ...[
        '--rendertiddler',
        '$:/plugins/tiddlywiki/pluginlibrary/library.template.html',
        'index.html',
        'text/plain',
      ] /* 生成插件库HTML文件 */,
      ...[
        '--deletetiddlers',
        '[[$:/UpgradeLibrary]] [[$:/UpgradeLibrary/List]]',
      ] /* 删掉中间内容 */,
    ],
  );

  // 最小化：HTML
  const HTMLPath = resolve(output, 'index.html');
  // index.html 的生成是异步而无法控制，很烦
  await waitForFile(HTMLPath);
  const result = await htmlMinify(readFileSync(HTMLPath, 'utf-8'), {
    caseSensitive: true,
    collapseBooleanAttributes: false,
    collapseInlineTagWhitespace: false,
    collapseWhitespace: true,
    conservativeCollapse: true,
    continueOnParseError: true,
    customAttrCollapse: /.*/,
    decodeEntities: true,
    html5: true,
    ignoreCustomFragments: [/<#[\s\S]*?#>/, /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/],
    includeAutoGeneratedTags: false,
    keepClosingSlash: false,
    maxLineLength: 0,
    minifyCSS: true,
    minifyJS: true,
    minifyURLs: true,
    preserveLineBreaks: false,
    preventAttributesEscaping: false,
    processConditionalComments: true,
    processScripts: ['text/html'],
    removeAttributeQuotes: true,
    removeComments: true,
    removeEmptyAttributes: true,
    removeEmptyElements: false,
    removeOptionalTags: true,
    removeRedundantAttributes: true,
    removeScriptTypeAttributes: true,
    removeStyleLinkTypeAttributes: true,
    removeTagWhitespace: true,
    sortAttributes: true,
    sortClassName: true,
    trimCustomFragments: true,
    useShortDoctype: true,
  });
  writeFileSync(HTMLPath, result);
  return plugins;
};
