/* eslint-disable no-cond-assign, default-case */
const escapeForRegexp = require('escape-string-regexp');

const URL_PATTERN = /url\(#([^ ]+?)\s*\)/g;
const defaultPattern = '[id]';

/**
 * @param {string} id
 * @param {string|Function} pattern
 */
function renameId(id, pattern) {
  const result = (typeof pattern === 'function' ? pattern(id) : pattern).toString();
  const re = new RegExp(escapeForRegexp('[id]'), 'g');
  return result.replace(re, id);
}

/**
 * @param {string|Function} [pattern]
 * @returns {Function}
 */
function plugin(pattern) {
  const p = pattern || defaultPattern;

  return (tree) => {
    const mappedIds = {};

    tree.match({ attrs: { id: /.*/ } }, (node) => {
      const { attrs } = node;
      const currentId = attrs.id;
      const newId = renameId(currentId, p);
      attrs.id = newId;

      mappedIds[currentId] = {
        id: newId,
        referenced: false,
        node
      };

      return node;
    });

    tree.match({ tag: /.*/ }, (node) => {
      const { attrs } = node;

      if (node.tag === 'style') {
        while (true) {
          const content = Array.isArray(node.content) ? node.content.join('') : node.content.toString();
          const match = URL_PATTERN.exec(content);
          if (match === null) {
            break;
          }

          const id = match[1];
          if (mappedIds[id]) {
            mappedIds[id].referenced = true;
            const re = new RegExp(escapeForRegexp(match[0]), 'g');
            node.content = content.replace(re, `url(#${mappedIds[id].id})`);
          }
        }
      }

      if ('attrs' in node === false) {
        return node;
      }

      Object.keys(attrs).forEach((attrName) => {
        const value = attrs[attrName];
        let id;
        let match;

        while ((match = URL_PATTERN.exec(value)) !== null) {
          id = match[1];
          if (mappedIds[id]) {
            mappedIds[id].referenced = true;
            const re = new RegExp(escapeForRegexp(match[0]), 'g');
            attrs[attrName] = value.replace(re, `url(#${mappedIds[id].id})`);
          }
        }

        let idObj;

        switch (attrName) {
          case 'href':
          case 'xlink:href':
            if (value.substring(0, 1) !== '#') {
              break;
            }

            id = value.substring(1);
            idObj = mappedIds[id];
            if (idObj) {
              idObj.referenced = false;
              attrs[attrName] = `#${idObj.id}`;
            }
            break;

          case 'for':
            if (node.tag !== 'label') {
              break;
            }

            id = value;
            idObj = mappedIds[id];
            if (idObj) {
              idObj.referenced = false;
              attrs[attrName] = idObj.id;
            }
            break;
        }
      });

      return node;
    });

    return tree;
  };
}

module.exports = plugin;