const fs = require('fs');
const cheerio = require('cheerio');
const { mergeWith, isArray } = require('lodash');
const { PurgeCSS } = require('purgecss');
const purgeHtml = require('purgecss-from-html');
const { cleanCSS } = require('./clean_css');
const { HTML_TO_REMOVE } = require('./constants');
const { die } = require('./utils');

const cleanHtml = (html) => {
  const $ = cheerio.load(html);

  HTML_TO_REMOVE.forEach((selector) => {
    $(selector).remove();
  });

  return $.html();
};

const mergePurgeCSSOptions = (...options) =>
  mergeWith(...options, (objValue, srcValue) => {
    if (isArray(objValue)) {
      return objValue.concat(srcValue);
    }

    return undefined;
  });

const getStartupCSS = async ({ htmlPaths, cssPaths, purgeOptions }) => {
  const content = htmlPaths.map((htmlPath) => {
    if (!fs.existsSync(htmlPath)) {
      die(
        `Could not find fixture "${htmlPath}". Have you run the fixtures? (bundle exec rspec spec/frontend/fixtures/startup_css.rb)`,
      );
    }

    const rawHtml = fs.readFileSync(htmlPath);
    const html = cleanHtml(rawHtml);

    return { raw: html, extension: 'html' };
  });

  const purgeCSSResult = await new PurgeCSS().purge({
    content,
    css: cssPaths,
    ...mergePurgeCSSOptions(
      {
        fontFace: true,
        variables: true,
        keyframes: true,
        blocklist: [/:hover/, /:focus/, /-webkit-/, /-moz-focusring-/, /-ms-expand/],
        safelist: {
          standard: ['brand-header-logo'],
        },
        // By default, PurgeCSS ignores special characters, but our utilities use "!"
        defaultExtractor: (x) => x.match(/[\w-!]+/g),
        extractors: [
          {
            extractor: purgeHtml,
            extensions: ['html'],
          },
        ],
      },
      purgeOptions,
    ),
  });

  return purgeCSSResult.map(({ css }) => cleanCSS(css)).join('\n');
};

module.exports = { getStartupCSS };