const fs = require('fs');
const path = require('path');
const csstree = require('css-tree');
const cheerio = require('cheerio');

const CSS_FILE = process.argv[2];
const BUILD_ROOT = process.argv[3];

const cssText = fs.readFileSync(CSS_FILE, 'utf-8');

const ast = csstree.parse(cssText);

function memoize(fn) {
  const cache = {};
  return (argument) => {
    if (argument in cache === false) {
      cache[argument] = fn(argument);
    }
    return cache[argument];
  };
}
const reduceCSSSelector = memoize((selector) => {
  return selector.split(
    /:(?=([^"'\\]*(\\.|["']([^"'\\]*\\.)*[^"'\\]*['"]))*[^"']*$)/g
  )[0];
});
const ALL_SELECTORS = new Set();
csstree.walk(ast, {
  visit: 'Rule',
  enter: function (node) {
    if (this.atrule) return;
    if (node.prelude.children) {
      node.prelude.children.forEach((node) => {
        const selectorString = reduceCSSSelector(csstree.generate(node));
        // console.log({ selectorString, atrule: this.atrule });
        if (selectorString === '0%') {
          console.log(node);
        }
        if (
          !selectorString ||
          selectorString === 'html' ||
          selectorString === 'body' ||
          selectorString === '*'
        ) {
          return;
        }
        if (selectorString.startsWith('.bc-')) {
          // Never included in the un-executed HTML
          return;
        }
        // if (!ALL_SELECTORS.has(selectorString)) {
        //   console.log({ selectorString });
        // }
        ALL_SELECTORS.add(selectorString);
      });
    }
  },
});

const ALL_SELECTORS_COPY = new Set([...ALL_SELECTORS]);

console.log(ALL_SELECTORS_COPY);

function* walker(root) {
  const files = fs.readdirSync(root);
  for (const name of files) {
    const filepath = path.join(root, name);
    const isDirectory = fs.statSync(filepath).isDirectory();
    if (isDirectory) {
      yield* walker(filepath);
    } else {
      yield filepath;
    }
  }
}

const dir = BUILD_ROOT;
if (!BUILD_ROOT) throw new Error('no BUILD_ROOT arg');

const allFilepaths = [];
for (const filepath of walker(dir)) {
  if (filepath.endsWith('/index.html')) {
    allFilepaths.push(filepath);
  }
}

function shuffle(array) {
  for (let i = array.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i

    // swap elements array[i] and array[j]
    // we use "destructuring assignment" syntax to achieve that
    // you'll find more details about that syntax in later chapters
    // same can be written as:
    // let t = array[i]; array[i] = array[j]; array[j] = t
    [array[i], array[j]] = [array[j], array[i]];
  }
}
shuffle(allFilepaths);

const SAMPLES = 10000;

for (const filepath of allFilepaths.slice(0, SAMPLES)) {
  // console.log(filepath, ALL_SELECTORS_COPY.size);
  const $ = cheerio.load(fs.readFileSync(filepath, 'utf-8'));
  for (const selector of ALL_SELECTORS_COPY) {
    try {
      // console.log({ selector });
      if ($(selector).length) {
        console.log(`'${selector}' is used`);
        ALL_SELECTORS_COPY.delete(selector);
      }
    } catch (err) {
      console.log('BAD SELECTOR STRING:', { selector });
      throw err;
    }
  }
}

console.log('COUNT BEFORE', ALL_SELECTORS.size);
console.log('COUNT AFTER ', ALL_SELECTORS_COPY.size);

console.log(
  `In ${SAMPLES} random built HTML pages, the following CSS selectors are never used...`
);
for (const selector of ALL_SELECTORS) {
  if (ALL_SELECTORS_COPY.has(selector)) {
    console.log(`- '${selector}'`);
  }
}
