#!/usr/bin/env node

const fs = require("fs");
const path = require("path");
const JSZip = require("jszip");
const Utils = require("../../utils");
const glob = require("glob");

function findWals(parentDir) {
  return new Promise((resolve, reject) => {
    glob("**/cPro2_Aluminum_1_1.wal", { cwd: parentDir }, (err, files) => {
      if (err) {
        return reject(err);
      }
      resolve(files.map(filePath => path.join(parentDir, filePath)));
    });
  });
}

function sumCountObjects(obj1, obj2) {
  return Object.keys(obj2).reduce((summaryObj, key) => {
    if (summaryObj[key] == null) {
      summaryObj[key] = obj2[key];
    } else {
      summaryObj[key] += obj2[key];
    }
    return summaryObj;
  }, Object.assign({}, obj1));
}

async function getAttributeDataFromWal(absolutePath) {
  const buffer = fs.readFileSync(absolutePath);
  const zip = await JSZip.loadAsync(buffer);
  const skinXml = await Utils.readXml(zip, "skin.xml");
  if (skinXml == null) {
    return [];
  }
  const rawXmlTree = await Utils.inlineIncludes(skinXml, zip);

  const nodeTypes = [];
  Utils.mapTreeBreadth(rawXmlTree, node => {
    if (node.type === "element") {
      nodeTypes.push({
        name: node.name.toLowerCase(),
        attributes:
          node.attributes == null
            ? []
            : Object.keys(node.attributes).map(attr => attr.toLowerCase()),
      });
    }
    return node;
  });
  return nodeTypes;
}

async function main(parentDir) {
  const errors = [];
  const paths = await findWals(parentDir);
  const attributeData = [];

  // Originally we moved to doing one skin at a time because we thougth it was
  // causing memory issues, now we know it's not, but it's still faster to do
  // one at a time for some reason.  ¯\_(ツ)_/¯
  for (const walPath of paths) {
    try {
      console.error(`Working on ${walPath}`);
      attributeData.push(...(await getAttributeDataFromWal(walPath)));
    } catch (e) {
      const errorLine = e.toString().split("\n")[0];
      errors.push({ [errorLine]: 1 });
      // TODO: Investigate these.
      console.error(`Error getting call data from ${walPath}`, e);
    }
  }

  const summary = attributeData.reduce((sum, attrs) => {
    if (sum[attrs.name] == null) {
      sum[attrs.name] = {
        count: 0,
        attributes: {},
      };
    }
    sum[attrs.name].count++;
    const nodeAttrs = sum[attrs.name].attributes;
    attrs.attributes.forEach(attr => {
      if (nodeAttrs[attr] == null) {
        nodeAttrs[attr] = 1;
      } else {
        nodeAttrs[attr]++;
      }
    });
    return sum;
  }, {});

  if (errors.length) {
    console.error(JSON.stringify(errors.reduce(sumCountObjects, {}), null, 2));
  }
  console.log(JSON.stringify(summary, null, 2));
}

main("/Volumes/Mobile Backup/skins/skins/random/Winamp Skins/Skins/");
