const htmlparser2 = require("htmlparser2");

const data = [];

function isFirstCharLowerCase(input) {
  return input.charAt(0) === input.charAt(0).toLowerCase();
}

function filterOutCommonClassNames(name) {
  return name.indexOf(":") !== -1 && isFirstCharLowerCase(name);
}

const parser = new htmlparser2.Parser(
  {
    onopentag(name, attribs) {
      const classNames = attribs.class;
      if (!classNames) return;

      // get all classnames as an array
      let list = classNames.split(" ");

      // filter out common class names such as `btn`, or `row` and keep only
      // those specific to this page, the convention is that those are always
      // lowercase and have a colon in it, for instance `intro:title`
      // then filter out the empty results
      list = list.filter(filterOutCommonClassNames);

      if (!list.length) return;

      data.push(list);
    },
    onclosetag(tagname) {},
    onend() {
      // console.log("done", data);
    },
  },
  { decodeEntities: true }
);

function processRecursively(parent, splitter) {
  for (let j = 0; j < parent.innerSelectors.length; j++) {
    const selector = parent.innerSelectors[j];
    const splitted = selector.split(splitter);
    const name = splitted[0];
    const innerSelector = splitted[1] || "";
    const target = parent.children[name] || {};
    const splittedModifiers = selector.split("--");
    const modifier = splittedModifiers[1];

    target.name = name;
    target.idx = target.idx || j;
    target.children = target.children || {};
    target.modifiers = target.modifiers || {};
    target.innerSelectors = target.innerSelectors || [];

    if (innerSelector && innerSelector.indexOf("--") === -1) {
      target.innerSelectors.push(innerSelector);
    }
    if (modifier) {
      target.modifiers[modifier] = true;
      console.log(target, "modifier");
    }

    processRecursively(target, /(?=[A-Z])/);

    parent.children[name] = target;
  }
}

function processData(allSelectors) {
  const modulos = {};

  allSelectors.forEach((selectors, i) => {
    const splitted = selectors[0].split(":");
    const name = splitted[0];
    const modulo = modulos[name] || {};

    modulo.name = name;
    modulo.idx = modulo.idx || i;
    modulo.children = {};
    modulo.modifiers = modulo.modifiers || {};
    modulo.innerSelectors = modulo.innerSelectors || [];

    for (let j = 0; j < selectors.length; j++) {
      const selector = selectors[j];
      const splitted = selector.split(":");
      const splittedModifiers = selector.split(":--");
      const innerSelector = splitted[1] || "";
      if (splittedModifiers[1]) {
        modulo.modifiers[splittedModifiers[1]] = true;
      } else if (innerSelector) {
        modulo.innerSelectors.push(innerSelector);
      }
    }
    modulos[name] = modulo;
  });

  for (const moduloName in modulos) {
    const modulo = modulos[moduloName];

    processRecursively(modulo, "__");

    modulos[moduloName] = modulo;
  }

  return modulos;
}

function getComment(firstBreak = true, indent, text = "Comment") {
  return (
    `${firstBreak ? "\n" : ""}${indent}// ${text}\n` +
    `${indent}// ${new Array(80 - 2 - indent.length).join("-")}\n`
  );
}

function getIndent(depth = 0) {
  return new Array(depth + 1).join("  ");
}

function getModifiers(depth, target) {
  let output = "";
  const indent = getIndent(depth + 1);
  const modifiers = Object.keys(target.modifiers);

  console.log(target.name, modifiers);

  if (modifiers.length) {
    for (let i = 0; i < modifiers.length; i++) {
      const modifier = modifiers[i];

      output += getComment(
        true,
        indent,
        `Modifier: ${target.name} -> ${modifier}`
      );
      output += `${indent}&--${modifier} {\n`;
      output += `${indent}}\n`;
    }
  }

  return output;
}

function dataToString(data) {
  let depth = 0;
  let indent = "";
  let output = "";
  let moduleIdx = 0;

  for (const moduloName in data) {
    const modulo = data[moduloName];
    depth = 0;
    indent = getIndent(depth);
    output += getComment(moduleIdx > 0, indent, `Module: ${modulo.name}`);
    output += `.${modulo.name}\\: {\n`;
    output += getModifiers(depth, modulo);

    for (const key in modulo.children) {
      const block = modulo.children[key];
      depth = 1;
      indent = getIndent(depth);
      output += getComment(true, indent, `Block: ${block.name}`);
      output += `${indent}&${block.name} {\n`;
      output += getModifiers(depth, block);

      for (const key in block.children) {
        const element = block.children[key];
        depth = 2;
        indent = getIndent(depth);
        output += getComment(
          true,
          indent,
          `Element: ${block.name} -> ${element.name}`
        );
        output += `${indent}&__${element.name} {\n`;
        output += getModifiers(depth, element);

        for (const key in element.children) {
          const subElement = element.children[key];
          depth = 3;
          indent = getIndent(depth);
          output += getComment(
            true,
            indent,
            `SubElement: ${block.name} -> ${element.name} -> ${subElement.name}`
          );
          output += `${indent}&${subElement.name} {\n`;
          output += getModifiers(depth, subElement);

          output += `${indent}}\n`;
        }

        output += `${getIndent(2)}}\n`;
      }

      output += `${getIndent(1)}}\n`;
    }

    output += `${getIndent(0)}}\n`;
    moduleIdx++;
  }

  return output; // .join("\n")
}

module.exports = function transform(template) {
  parser.write(template);
  parser.end();

  const ast = processData(data);
  // TODO: deep sort
  const output = dataToString(ast);

  return output;
};
