// HTML Formatter
// https://github.com/uznam8x/html-formatter
// MIT License

const single = [
  'br', 'hr', 'img', 'input', 'meta', 'link',
  'col', 'base', 'param', 'track', 'source', 'wbr',
  'command', 'keygen', 'area', 'embed', 'menuitem'
];

const closing = function(el) {
  el = el.replace(/<([a-zA-Z\-0-9]+)[^>]*>/g, function(match, capture) {
    if (single.indexOf(capture) > -1) {
      return (match.substring(0, match.length - 1) + ' />').replace(/\/\s\//g, '/');
    }
    return match.replace(/[\s]?\/>/g, '></' + capture + '>');
  });
  return el;
};

const entity = function(el) {
  el = el.replace(/(<textarea[^>]*>)\n\s+/g, '$1');
  el = el.replace(/\s+<\/textarea>/g, '</textarea>');
  el = el.replace(/<textarea[^>]*>((.|\n)*?)<\/textarea>/g, function(match, capture) {
    return match.replace(capture, function(match) {
      return match
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/\//g, '&#47;')
        .replace(/"/g, '&#34;')
        .replace(/'/g, '&#39;')
        .replace(/\n/g, '&#13;')
        .replace(/%/g, '&#37;')
        .replace(/\{/g, '&#123;')
        .replace(/\}/g, '&#125;')
        .replace(/\s/g, '&nbsp;');
    });
  });
  return el;
};

const minify = function(el)  {
  return el
    .replace(/\n|\t/g, '')
    .replace(/[a-z]+="\s*"/ig, '')
    .replace(/>\s+</g, '><')
    .replace(/\s+/g, ' ')
    .replace(/\s>/g, '>')
    .replace(/class=["']\s/g, function(match) {
      return match.replace(/\s/g, '');
    })
    ;
};

const convert = {
  comment: [],
  line: [],
  script: []
};

const preserveScripts = function (el) {
  convert.script = [];
  el = el.replace(/(<script[^>]*>)([\s\S]*?)(<\/script>)/gi, function (match, open, content, close) {
    if (!content.trim()) return match;
    convert.script.push(content);
    return open + '[#s# : ' + (convert.script.length - 1) + ' : #s#]' + close;
  });
  return el;
};

const restoreScripts = function (el) {
  convert.script.forEach(function (content, index) {
    el = el.replace('[#s# : ' + index + ' : #s#]', content);
  });
  return el;
};

const comment = function (el) {
  convert.comment = [];

  el = el.replace(/(<!--(.|\n)*?-->)/g, function (match) {
    convert.comment.push(match);
    return '<!-- [#!# : ' + (convert.comment.length - 1) + ' : #!#] -->';
  });
  return el;
};

const line = function (el) {
  convert.line = [];
  let i = -1;
  el = el.replace(/<[^>]*>/g, function (match) {
    convert.line.push(match);
    i++;
    return '\n[#-# : ' + i + ' : ' + match + ' : #-#]\n';
  });
  el = el.replace(/\n\n/g, '\n');
  return el;
};

const tidy = function (el) {
  let tab = '';
  convert.line.forEach(function (source, index) {
    el = el.replace('[#-# : ' + index + ' : ' + source + ' : #-#]', function (match) {
      const prevLine = '[#-# : ' + (index - 1) + ' : ' + convert.line[index - 1] + ' : #-#]';
      tab += '\t';
      let remove = 0;
      if (index === 0) remove++;
      if (match.indexOf('#-# : ' + (index) + ' : </') > -1) remove++;
      if (prevLine.indexOf('<!doctype') > -1) remove++;
      if (prevLine.indexOf('<!--') > -1) remove++;
      if (prevLine.indexOf('/> : #-#') > -1) remove++;
      if (prevLine.indexOf('#-# : ' + (index - 1) + ' : </') > -1) remove++;
      if (match.indexOf('<!--') > -1) {
        match = match.replace('<!-- [#!# :', '<!-- [#!# %' + (tab.length - remove) + '% :');
      }
      tab = tab.substring(0, tab.length - remove);
      return tab + match.replace('[#-# : ' + index + ' : ', '').replace(' : #-#]', '');
    });
  });


  el = el.replace(/>[^<]*?[^><\/\s][^<]*?<\/|>\s+[^><\s]|<script[^>]*>\s+<\/script>|<(\w+)>\s+<\/(\w+)|<(\w+)[^>]*>\s<\/(\w+)>|<([\w\-]+)[^>]*[^\/]>\s+<\/([\w\-]+)>/g, function(match) {
    return match.replace(/\n|\t/g, '');
  })

  const generateTab = function(cnt){
    let t = '';
    for (let c = 0; c < cnt; c++) {
      t += '\t';
    }
    return t;
  }
  convert.comment.forEach(function (source, index) {
    el = el.replace(new RegExp('<!--[^>]*' + index + ' : #!#] -->', 'g'), function (match) {
      const cnt = /%(\d+)%/g.exec(match);
      const t = generateTab(cnt[1]);
      return source.replace(/\n/g, '\n'+t);
    });
  });

  return el.substring(1, el.length - 1);
};

const render = function (el, opt) {
  el = closing(el);
  el = preserveScripts(el);
  el = comment(el);
  el = entity(el);
  el = minify(el);
  el = line(el);
  el = tidy(el);
  el = restoreScripts(el);

  return el;
};

// Export for ES modules
export { closing, entity, minify, render };
export default render;
