'use strict';

let css;
try {
  css = require('css');
} catch (error) {
  if (error.code === 'MODULE_NOT_FOUND') {
    css = require('@adobe/css-tools');
  } else {
    throw error;
  }
}

const fs = require('fs');
const objUtil = require('../../utils/object');
const resolveModule = require('../../utils/resolve');

module.exports = (hexo) => {

  function resolveHighlight(name) {
    if (!name) {
      name = 'github-gist';
    }
    const cssName = name.toLowerCase().replace(/([^0-9])\s+?([^0-9])/g, '$1-$2').replace(/\s/g, '');
    let file = resolveModule('highlight.js', `styles/${cssName}.css`);
    if (cssName === 'github-gist' && !fs.existsSync(file)) {
      file = resolveModule('highlight.js', 'styles/github.css');
    }
    let backgroundColor;
    if (fs.existsSync(file)) {
      const content = fs.readFileSync(file, 'utf8');
      css.parse(content).stylesheet.rules
        .filter(rule => rule.type === 'rule' && rule.selectors.some(selector => selector.endsWith('.hljs')))
        .flatMap(rule => rule.declarations)
        .forEach(declaration => {
          if (declaration.property === 'background' || declaration.property === 'background-color') {
            backgroundColor = declaration.value;
          }
        });
    } else {
      hexo.log.error(`[Fluid] highlightjs style '${name}' not found`);
      return {};
    }
    if (backgroundColor === 'white' || backgroundColor === '#ffffff') {
      backgroundColor = '#fff';
    }
    return { file, backgroundColor };
  }

  function resolvePrism(name) {
    if (!name) {
      name = 'default';
    }
    let cssName = name.toLowerCase().replace(/[\s-]/g, '');
    if (cssName === 'prism' || cssName === 'default') {
      cssName = '';
    } else if (cssName === 'tomorrownight') {
      cssName = 'tomorrow';
    }
    let file = resolveModule('prismjs', `themes/${cssName ? 'prism-' + cssName : 'prism'}.css`);
    if (!fs.existsSync(file)) {
      file = resolveModule('prism-themes', `themes/${cssName}.css`);
    }
    if (!fs.existsSync(file)) {
      hexo.log.error(`[Fluid] prismjs style '${name}' not found`);
      return {};
    }
    return { file };
  }

  const config = hexo.theme.config;
  if (!config.code || !config.code.highlight.enable) {
    return;
  }

  if (config.code.highlight.lib === 'highlightjs') {
    // Force set hexo config
    hexo.config.prismjs = objUtil.merge({}, hexo.config.prismjs, {
      enable: false
    });
    hexo.config.highlight = objUtil.merge({}, hexo.config.highlight, {
      enable     : true,
      hljs       : true,
      wrap       : false,
      auto_detect: true,
      line_number: config.code.highlight.line_number || false
    });
    hexo.config.syntax_highlighter = 'highlight.js';  // hexo v7.0.0+ config
    hexo.theme.config.code.highlight.highlightjs = objUtil.merge({}, hexo.theme.config.code.highlight.highlightjs, {
      light: resolveHighlight(hexo.theme.config.code.highlight.highlightjs.style),
      dark : hexo.theme.config.dark_mode.enable && resolveHighlight(hexo.theme.config.code.highlight.highlightjs.style_dark)
    });

    hexo.extend.filter.register('after_post_render', (page) => {
      if (hexo.config.highlight.line_number) {
        page.content = page.content.replace(/<figure[^>]+?highlight.+?<td[^>]+?code[^>]+?>.*?(<pre.+?<\/pre>).+?<\/figure>/gims, (str, p1) => {
          if (/<code[^>]+?mermaid[^>]+?>/ims.test(p1)) {
            return p1.replace(/(class="[^>]*?)hljs([^>]*?")/gims, '$1$2').replace(/<br>/gims, '\n');
          }
          return str;
        });
      } else {
        page.content = page.content.replace(/(?<!<div class="code-wrapper">)<pre.+?<\/pre>/gims, (str) => {
          if (/<code[^>]+?mermaid[^>]+?>/ims.test(str)) {
            return str.replace(/(class=".*?)hljs(.*?")/gims, '$1$2');
          }
          return `<div class="code-wrapper">${str}</div>`;
        });
      }

      // 适配缩进型代码块
      page.content = page.content.replace(/<pre><code>/gims, (str) => {
        return '<pre><code class="hljs">';
      });

      return page;
    });
  } else if (config.code.highlight.lib === 'prismjs') {
    // Force set hexo config
    hexo.config.highlight = objUtil.merge({}, hexo.config.highlight, {
      enable: false
    });
    hexo.config.prismjs = objUtil.merge({}, hexo.config.prismjs, {
      enable     : true,
      preprocess : config.code.highlight.prismjs.preprocess || false,
      line_number: config.code.highlight.line_number || false
    });
    hexo.config.syntax_highlighter = 'prismjs';  // hexo v7.0.0+ config
    hexo.theme.config.code.highlight.prismjs = objUtil.merge({}, hexo.theme.config.code.highlight.prismjs, {
      light: resolvePrism(hexo.theme.config.code.highlight.prismjs.style),
      dark : hexo.theme.config.dark_mode.enable && resolvePrism(hexo.theme.config.code.highlight.prismjs.style_dark)
    });

    hexo.extend.filter.register('after_post_render', (page) => {
      page.content = page.content.replace(/(?<!<div class="code-wrapper">)<pre.+?<\/pre>/gims, (str) => {
        if (/<code[^>]+?mermaid[^>]+?>/ims.test(str)) {
          if (hexo.config.highlight.line_number) {
            str = str.replace(/<span[^>]+?line-numbers-rows[^>]+?>.+?<\/span><\/code>/, '</code>');
          }
          str = str.replace(/<pre[^>]*?>/gims, '<pre>')
            .replace(/(class=".*?)language-mermaid(.*?")/gims, '$1mermaid$2')
            .replace(/<span[^>]+?>(.+?)<\/span>/gims, '$1');
          return str;
        }
        return `<figure><div class="code-wrapper">${str}</div></figure>`;
      });

      // 适配缩进型代码块
      page.content = page.content.replace(/<pre><code>/gims, (str) => {
        return '<pre class="language-none"><code class="language-none">';
      });

      return page;
    });
  }
};
