"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _postcss = _interopRequireDefault(require("postcss"));

var _fs = _interopRequireDefault(require("fs"));

var _checkIsPatternsMatchFilename = require("../../loaderConfigs/checkIsPatternsMatchFilename");

var _ErrorHandler = require("./ErrorHandler");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

// import { RawSource } from 'webpack-sources';
const ignoreVals = ['--zd_size', '--zd_font_size', '--size', '--size_'];
let variablesRead = {};
const supportedProps = ['font-size', 'margin', 'margin-top', 'margin-bottom', 'margin-left', 'margin-right', 'padding', 'padding-top', 'padding-bottom', 'padding-left', 'padding-right', '^top', '^right', '^bottom', '^left', '^width', 'min-width', 'max-width', '^height', 'min-height', 'max-height', 'text-indent', 'clip', 'flex-basis', 'row-gap', 'gap', 'column-gap', 'flex']; // const avoidProps = [];
// -- is issue IO --

/*
issues eg : 
issues = ['--zd_size', '--zd_font_size', '--size', '--size_'];
input : 
--zd_size
output : 
true
comment : 
do not execute when --zd_size comes as prop 
*/

function isIgnoreValuePresent(ignoreVals, prop) {
  let present = false;
  ignoreVals.forEach(issue => {
    if (prop && prop.includes(issue)) {
      present = true;
    }
  });
  return present;
} // -- to convert the hyphen values to values --

/*
input : 
var(--zdt_uploadlist_default_width)
output : 
--zdt_uploadlist_default_width

comment : 
to make the variable object using the output as key and decl.prop such as font-size as value 
*/


function extractVariableName(val) {
  return val.replace(/calc\((.+)\)/gi, '$1').replace(/var\((.+)\)/gi, '$1').replace('-1', '').replace('*', '').replace('\n', '').trim();
}

function variableConvertor(rootOriginal, variables, settingsObject) {
  rootOriginal.walkRules(rule => {
    rule.nodes.forEach((decl, index) => {
      const prevNode = rule.nodes[index - 1];
      const currentNode = rule.nodes[index];

      if (decl.prop && decl.prop.includes('--')) {
        if (prevNode && prevNode.type === 'comment' && prevNode.text.toLowerCase() === 'variable:ignore') {
          return;
        }

        if (isIgnoreValuePresent(ignoreVals, decl.prop)) {
          return;
        }

        if (settingsObject[variables[decl.prop]]) {
          /* if there is no value for property, set it to default so that undefined doesn't get called as key */
          if (!variables[decl.prop]) {
            variables[decl.prop] = 'default';
          }

          const pxReplacement = settingsObject[variables[decl.prop]].replacements.px;
          const valArr = decl.value.split(' '); // single values are considered in the above array and converted below

          valArr.forEach((value, index) => {
            if (value.includes('px')) {
              const num = value.replace('px', '');
              valArr[index] = pxReplacement.replace('$$', num);
            }
          });
          currentNode.value = valArr.join(' ');
        }
      }
    });
  });
  return rootOriginal;
}

function createFolderIfNonExistant(path) {
  if (!_fs.default.existsSync(path)) {
    _fs.default.mkdirSync(path, {
      recursive: true
    });
  }
}

function createFileIfNonExistant(path, content) {
  if (_fs.default.existsSync(path)) {
    _fs.default.writeFileSync(path, content, 'utf-8');
  }
}

class VariableConversionCollector {
  constructor(options = {}) {
    this.configFile = options.configFile;
    this.patterns = options.patterns;
    this.initializeFiles();
  } // eslint-disable-next-line class-methods-use-this


  initializeFiles() {
    createFolderIfNonExistant('./.cli/logs/');
    createFolderIfNonExistant('./.cli/config/variables/');
    createFolderIfNonExistant('./.cli/config/selectorWeight/');
    createFileIfNonExistant('./.cli/logs/unassignedVariables.log', '{}');
    createFileIfNonExistant('./.cli/logs/css_error.log', '{}');
  }

  apply(compiler) {
    const {
      patterns
    } = this;
    const variables = {};
    const unassigned = {}; // console.log(windowsModification([this.filename])[0]);

    const rawdata = _fs.default.readFileSync(this.configFile);

    const data = JSON.parse(rawdata);
    const {
      settings: settingsObject,
      errorLog: errorLogStatus,
      errorInConsole: errorConsoleStatus,
      errorsAllowed,
      strictMode
    } = data; // If theres is no setting for default prop in settingsObject, set one.

    if (!settingsObject.default) {
      settingsObject.default = {
        allowed: ['px', 'em', 'fit-content', 'auto', '%', 'inherit', '-moz-fit-content', 'vh', '0', 'initial', 'vw'],
        replacements: {
          px: 'var(--zd_size$$)'
        },
        range: {
          start: -99999,
          end: 99999
        }
      };
    }
    /* 
    purpose of tap : to create a variable object such as:
    {
      --zdt_uploadlist_default_width : width,
      --zdt_uploadlist_default_height : height,
    }
    which will help in the conversion further
    */


    if (_fs.default.existsSync('./.cli/config/variables/variableMapping.json')) {
      variablesRead = JSON.parse(_fs.default.readFileSync('./.cli/config/variables/variableMapping.json', 'utf-8'));
      Object.keys(variablesRead.changes).forEach(key => {
        variables[key] = variablesRead.changes[key];
      });
    }

    console.log("Variable conversion");
    compiler.hooks.compilation.tap('VariableConversionCollector', compilation => {
      compilation.hooks.optimizeModules.tap('VariableConversionCollector', modulesIterable => {
        const modules = Array.from(modulesIterable);
        const mods = modules.filter(x => x.type.includes('css'));
        mods.forEach(module => {
          const rootOriginal = _postcss.default.parse(module.content);

          const filename = module.issuer.resource;

          if (!filename.includes('node_modules')) {
            rootOriginal.walkRules(rule => {
              rule.walkDecls(decl => {
                decl.value.split(' ').forEach(val => {
                  if (val && val.includes('--') && !new RegExp(ignoreVals.join('|'), 'gi').test(val) && decl.prop) {
                    const extractedValue = extractVariableName(val);

                    if (!variables[extractedValue]) {
                      variables[extractedValue] = decl.prop;
                    } else if (new RegExp(supportedProps.join('|'), 'gi').test(decl.prop)) {
                      // console.log(
                      //   `${extractedValue} : ${variables[extractedValue]} already exists please check!`
                      // );
                      if (errorsAllowed.MULTIPLE_OCCURANCES) {
                        const errObj = {
                          decl,
                          type: 'MULTIPLE_OCCURANCES',
                          filename,
                          message: `${extractedValue} : ${variables[extractedValue]} already exists please check!`
                        };

                        _ErrorHandler.errHandler.errorTable.push(errObj);

                        _ErrorHandler.errHandler.errorFunction(errObj);
                      }
                    } // console.log(decl.prop);

                  } else if (/^--/gi.test(decl.prop) && val.trim() !== '' && !variables[decl.prop]) {
                    if (!Object.keys(variablesRead.ignore).includes(decl.prop)) {
                      unassigned[decl.prop] = variables[decl.prop];
                    }
                  }
                });
              });
            });
            /*
             current value example: 
             {
                --zdt_uploadlist_default_width : --zd_upload_width,
                --zd_upload_width : width
             }
             expected value : 
             {
               --zdt_uploadlist_default_width : width,
               --zd_upload_width : width
             }
            
             conversion is done in the while loop below
            */

            Object.keys(variables).forEach(key => {
              while (variables[variables[key]]) {
                variables[key] = variables[variables[key]];
              }
            });
          }
        });
      }); // -- conversion for the root using variableConvertor --

      /* 
      input : 
      .a{
        padding : 20px 
      }
      output :
      // on settingObject file : 
      { padding : { replacements : { px : 'zd_size$$' }}} 
      .a{
        padding : zd_size20;
      }
      */

      compilation.hooks.optimizeModules.tap('VariableConversionCollector', modules => {
        const mods = Array.from(modules).filter(x => x.type.includes('css'));
        mods.forEach(module => {
          const filename = module.issuer.resource;
          /*
            input : 
            filename : 'D:/MyWork/..../desk_client_app/supportapp/src/components/Avatar/Avatar.module.css,
          
              patterns.cssVariableReplacement: 
            // include src folder, include deskapp folder, exclude node modules
            [
              "src",
              "deskapp",
              "!node_modules"
            ]
            
            output : 
            true or false
          */

          if ((0, _checkIsPatternsMatchFilename.checkIsPatternsMatchFilename)(patterns, filename) === false) {
            return;
          }

          const rootOriginal = _postcss.default.parse(module.content);

          module.content = variableConvertor(rootOriginal, variables, settingsObject).toString();
        });
      });
    });
    /*
      purpose of tap : to display the errors encountered so far 
      input : 
      all css files 
      output : 
      all errors that are present in the errTable arr
    */

    compiler.hooks.afterEmit.tap('error-display', () => {
      const {
        errors,
        errorTable: errTable
      } = _ErrorHandler.errHandler;

      if (Object.keys(unassigned).length > 0 && strictMode) {
        console.log();
        console.log(unassigned);
        console.log();
        let str = '{\n';
        Object.keys(unassigned).forEach(key => {
          str += `"${key}" : "${unassigned[key]}",\n`;
        });
        str += '}';

        _fs.default.writeFileSync('./.cli/logs/unassignedVariables.log', str, 'utf-8');

        throw new Error('^^^ Variables above have not been assigned! ^^^');
      }

      const avlTypes = new Set([]); // eslint-disable-next-line array-callback-return, consistent-return

      const srtArr = errTable.sort((a, b) => {
        avlTypes.add(a.type);
        avlTypes.add(b.type);

        if (a.type < b.type) {
          return -1;
        }
      });

      if (errorConsoleStatus) {
        const errorHandler = new _ErrorHandler.ErrorHandler();
        avlTypes.forEach(type => {
          console.log('---------------------------------------------------------------------------------------------------------------------------');
          console.log(`Error Type : ${type}`);
          console.log('---------------------------------------------------------------------------------------------------------------------------');
          srtArr.forEach(err => {
            if (err.decl.prop && err.decl.value && err.type === type) {
              errorHandler.printError(err);
            }
          });
          console.log('---------------------------------------------------------------------------------------------------------------------------');
        });
      }

      if (errorLogStatus) {
        _fs.default.writeFileSync('./.cli/logs/css_error.log', '');

        console.log('writing to logFile...');

        if (errors.length > 0) {
          errors.forEach((err, index) => {
            if (errTable[index].decl.prop && errTable[index].decl.value) {
              _fs.default.appendFileSync('./.cli/logs/css_error.log', err);
            }
          });
        }
      }
    });
  }

}

var _default = VariableConversionCollector;
exports.default = _default;