"use strict";

const postcss = require('postcss');

const fs = require('fs');

const path = require('path');

const {
  ErrorHandler
} = require('./ErrorHandler');

const errHandler = new ErrorHandler();
const convertableProps = {
  'font-size': true,
  margin: true,
  'margin-left': true,
  'margin-right': true,
  'margin-top': true,
  'margin-bottom': true,
  padding: true,
  'padding-top': true,
  'padding-bottom': true,
  'padding-left': true,
  'padding-right': true,
  width: true,
  'min-width': true,
  'max-width': true,
  height: true,
  'min-height': true,
  'max-height': true,
  top: true,
  bottom: true,
  left: true,
  right: true,
  'text-indent': true,
  clip: true,
  'flex-basis': true,
  'row-gap': true,
  gap: true,
  'column-gap': true,
  flex: true
};
const constantValues = {
  inherit: true,
  initial: true,
  auto: true,
  'fit-content': true,
  unset: true,
  cover: true,
  contain: true,
  top: true,
  bottom: true,
  left: true,
  center: true,
  right: true
};

function getNumericValue(value) {
  if (value.includes('var')) {
    return parseInt(value.replace(/var\(--zd_size(\d+)\)/gi, '$1').replace(/var\(--zd_font_size(\d+)\)/gi, '$1'));
  }

  if (value.includes('rect')) {
    return parseInt(value.replace('rect(', '').replace(')', '').replace(',', ''));
  } // Not need for this dum loop
  // allowed.forEach(alwdUnit => {
  //   if (value.includes(alwdUnit)) {
  //     return parseInt(value);
  //   }
  // });


  if (constantValues[value.toLowerCase()]) {
    return 1;
  }

  return parseInt(value);
}

function pxToCalc(value) {
  const arr = value.split(' ');
  arr.forEach((val, index) => {
    ['px'].forEach(unit => {
      const valWithUnit = new RegExp(`(\\d+)${unit}`, 'gi');

      if (valWithUnit.test(val)) {
        arr[index] = val.replace(valWithUnit, '(var(--zd_size$1))');
      }
    });
  });
  return arr.join(' ');
}

const singleConvertor = ({
  value,
  changeVal,
  details,
  range,
  allowed
}) => {
  const {
    path,
    filename,
    decl
  } = details;

  if (decl.prop === 'background-position') {
    if (isNaN(parseInt(value))) {
      // console.log(`${value} skipped`);
      return;
    }
  }

  if (allowed && allowed.includes(decl.value) && decl.value.toString() !== '0') {
    return decl.value;
  }

  if (getNumericValue(value) >= range.start && getNumericValue(value) <= range.end || getNumericValue(value) === 0) {
    if (value.trim() === '0px') {
      return '0';
    }

    let retVal = value.replace(/(\d+)px/gi, changeVal.replace('$$', '$1'));

    if (/^-var/.test(retVal)) {
      retVal = `calc( ${retVal.substring(1)} * -1 )`;
    }

    return retVal;
  } // if (!value.includes('rect')) {
  // if(unitErrorVal && unitErrorVal != '0' ){
  // console.log(value, 'not within range')


  const errObj = {
    decl,
    type: 'RANGE_ERROR',
    filename,
    message: `value (${value}) (${typeof value}) not within range (${range.start},${range.end})\r`,
    path: path
  };
  errHandler.errorTable.push(errObj);
  errHandler.errorFunction(errObj);
  return;
};

module.exports = {
  plugin: postcss.plugin('postcss-variable-report', cssVariableReplacementConfig => {
    const rawdata = fs.readFileSync(cssVariableReplacementConfig);
    const data = JSON.parse(rawdata);
    const {
      errorsAllowed,
      settings: settingsObject // errorLog: errorLogStatus,
      // errorInConsole: errorConsoleStatus

    } = data; // const keys = Object.keys(settingsObject);

    errHandler.setAllowedErrs(errorsAllowed);
    const replacementArray = [];
    Object.keys(settingsObject).forEach(key => {
      Object.values(settingsObject[key].replacements).forEach(val => {
        if (!replacementArray.includes(val)) {
          replacementArray.push(val);
        }
      });
    });
    let regValStr = '';
    replacementArray.forEach((val, index) => {
      if (index !== replacementArray.length - 1) {
        regValStr += `${val.replace('$$', '\\d+').replace('(', '\\(').replace(')', '\\)')}|`;
      } else {
        regValStr += `${val.replace('$$', '\\d+').replace('(', '\\(').replace(')', '\\)')}`;
      }
    });
    const valRegex = new RegExp(regValStr, 'gi');
    return rootOriginal => {
      // console.log(rootOriginal.source.input.from, 'passed through variable Plugin');
      rootOriginal.walkRules(rule => {
        // rule.nodes[-1] = {}
        // need map, forEach fine less memory
        rule.nodes.forEach((decl, position) => {
          // case font-size
          const commentStr = 'variable:ignore';
          const prevNode = rule.nodes[position - 1];
          const fromPath = rootOriginal.source.input.from; // this will be problem for linux and mac use require('path').sep
          // split not need use slice and lastIndexOf less memory

          const filename = fromPath.split(path.sep).pop(); // if(filename.includes('AddFormResponsive.module.css'){
          // }

          if (prevNode && prevNode.type === 'comment' && prevNode.text.toLowerCase().includes(commentStr)) {
            const errObj = {
              decl,
              type: 'DECLARATION_IGNORED',
              filename,
              message: 'Declaration Ignored',
              path: fromPath
            };
            errHandler.errorTable.push(errObj);
            errHandler.DECLARATION_IGNORED(errObj);
            return;
          }

          if (settingsObject[decl.prop] && !decl.value.includes('var(--')) {
            const settings = settingsObject[decl.prop];
            const {
              allowed,
              range
            } = settings; // suggestion filter  !decl.value.includes('calc')
            // Reason below some of logic happen based on this

            const unit = decl.value.toString() // no need round braket since you do not need group for less memory
            .replace(/\d+/gi, '').replace('var(--zd_size)', 'px').replace('var(--zd_font_size)', 'px').replace('rect(', '').replace(')', '').replace('px,', 'px').replace(',', '').split(' ').filter(x => x !== ''); // unit = unit.replace(unit, unit.replace('-',''))
            // console.log('unit : ');
            // console.log(unit);
            // if (decl.prop === 'height') {
            //   console.log(decl.prop, unit, 'case 1');
            // }

            unit.forEach((val, index) => {
              allowed.forEach(alwdVal => {
                if (val.includes(alwdVal)) {
                  // ## for what purpose
                  unit[index] = val // .replace(new RegExp('(\\d+).(\\d+)(\\w+)', 'gi'), '$3')
                  .replace(`-${alwdVal}`, `${alwdVal}`).replace(`-.${alwdVal}`, `${alwdVal}`).replace(`${alwdVal},`, `${alwdVal}`);
                }
              });
            });
            let unitError = false;
            let unitErrorVal = '';
            unit.forEach(val => {
              if (!val.includes('calc') && decl.prop !== 'clip') {
                if (!allowed.includes(val.toString())) {
                  unitError = true;
                  unitErrorVal = val;
                }
              }
            }); // if (decl.prop === 'height') {
            //   console.log(decl.prop, unitErrorVal, unitError, unit, 'case 2');
            // }
            // console.log(allowed, replacements, range)

            if (!unitError) {
              let calcValue = false;

              if (decl.value.includes('calc')) {
                decl.value = pxToCalc(decl.value);
                calcValue = true;
              } // use variable decl.value.split(' ')


              if (range && !calcValue) {
                // console.log('multiple :', decl.value)
                const tempVal = decl.value; // if (decl.prop === 'height') {
                //   console.log(decl.prop, tempVal, decl.value, allowed, 'case 3');
                // }
                // if (decl.prop === 'height') {
                //   console.log('allowed!', decl.prop, decl.value, allowed);
                // }

                let newVal = '';
                let splitValues = decl.value.split(' ');
                splitValues = splitValues.filter(val => val.trim() !== '');
                splitValues = splitValues.map(val => val.replace(/\r|\t|\n/gi, ''));
                splitValues.forEach(singleVal => {
                  newVal += `${singleConvertor({
                    value: singleVal,
                    changeVal: settings.replacements.px,
                    details: {
                      decl,
                      filename,
                      path: fromPath
                    },
                    range,
                    allowed
                  })} `;
                });
                decl.value = newVal; // if (decl.prop === 'height') {
                //   console.log(decl.prop, tempVal, newVal, 'case 4');
                // }
              }
            } else {
              if (!decl.value.includes('calc')) {
                // addError(` prop: ${decl.prop} ,\n value : ${decl.value} ,\n filename : ${filename} ,\n filepath : ${path} ,\n line : ${decl.source.start.line} ,\n unit : ${unitErrorVal} ,\n message : ${unitErrorVal} (Unit) Not Allowed \r`);
                const errObj = {
                  decl,
                  filename,
                  unitErrorVal: unitErrorVal,
                  path: fromPath
                };

                if (unitErrorVal.trim() === '.') {
                  errObj.type = 'DECIMAL_CHECK';
                  errObj.message = `${unitErrorVal} (Decimal Value) Please check`;
                  errHandler.errorTable.push(errObj);
                  errHandler.DECIMAL_CHECK(errObj);
                } else if (unitErrorVal.includes('.') && !unitErrorVal.includes('%')) {
                  errObj.type = 'DECIMAL_REJECT';
                  errObj.message = `${unitErrorVal} (Decimal Value) Not Allowed \r`;
                  errHandler.errorTable.push(errObj);
                  errHandler.DECIMAL_REJECT(errObj);
                } else {
                  if (!unitErrorVal.includes('%')) {
                    errObj.type = 'UNIT_ERROR';
                    errObj.message = `${unitErrorVal} (Unit) Not Allowed`;
                    errHandler.errorTable.push(errObj);
                    errHandler.UNIT_ERROR(errObj);
                  }
                }
              } else {
                decl.value = pxToCalc(decl.value);
              }
            }
          } else {
            if (settingsObject[decl.prop] && decl.value && decl.value.includes('px') && decl.value.includes('var(--')) {
              const valArr = decl.value.split(' ');
              const settings = settingsObject[decl.prop];
              const {
                range,
                allowed
              } = settings;
              const convertedVals = valArr.map(val => {
                if (val.includes('px')) {
                  const convertedVal = singleConvertor({
                    value: val,
                    changeVal: settings.replacements.px,
                    details: {
                      decl,
                      filename,
                      path: fromPath
                    },
                    range,
                    allowed
                  });
                  return convertedVal ? convertedVal : val;
                }

                return val;
              });
              decl.value = convertedVals.join(' ');
            }

            if (decl.prop && decl.value && !decl.prop.includes('--') && valRegex.test(decl.value) && (settingsObject[decl.prop] || convertableProps[decl.prop]) && decl.value.includes('var') && !decl.value.includes('calc')) {
              const errObj = {
                decl,
                type: 'VARIABLE_PRESENT',
                filename,
                message: `value (${decl.value}) has var in it, kindly check`,
                path: fromPath
              };
              errHandler.errorTable.push(errObj);
              errHandler.VARIABLE_PRESENT(errObj);
            }
          }
        });
      });
    };
  }),
  errors: errHandler.errors,
  errTable: errHandler.errorTable,
  errHandler
};