'use strict';

const core = require('@sankhyalabs/core');
const filterItemType_enum = require('./filter-item-type.enum-a7ffdaa6.js');
const index = require('./index-62760a9c.js');

class PersonalizedFilterUtils {
  /**
   * Cria uma expressão de filtro a partir de um IExpressionItem.
   * @param expressionItem - Objeto com os parâmetros necessários para montar a expressão.
   * @returns Retorna a expressão de filtro.
   */
  static buildFilterExpression(expressionItem) {
    var _a;
    if (expressionItem == undefined) {
      return;
    }
    let value = (_a = this.buildVariableParameterValue(expressionItem)) !== null && _a !== void 0 ? _a : undefined;
    let expression = expressionItem.expression || "";
    let commas = "'";
    if (expressionItem.paramVariable) {
      commas = "";
    }
    switch (expressionItem.operand) {
      case "IN":
        expression += ` ${index.FilterOperand[expressionItem.operand]} (${value})`;
        break;
      case "NULL":
      case "NOT_NULL":
        expression += ` IS ${index.FilterOperand[expressionItem.operand]}`;
        break;
      case "LIKE":
        expression += ` LIKE '%${value}%'`;
        break;
      case "START_WITH":
        expression += ` LIKE '${value}%'`;
        break;
      case "FINISHED_WITH":
        expression += ` LIKE '%${value}'`;
        break;
      default:
        if (expressionItem.operand) {
          expression += ` ${index.FilterOperand[expressionItem.operand]}`;
        }
        if (['string', 'number'].includes(typeof value)) {
          value = isNaN(value) ? `${commas}${value}${commas}` : value;
          expression += ` ${value}`;
        }
    }
    return expression;
  }
  /**
   * Obtém o valor do parâmetro a partir de um IExpressionItem.
   * @param expressionItem - Objeto com os parâmetros necessários para montar a expressão.
   * @returns Retorna o valor do parâmetro.
   */
  static buildVariableParameterValue(expressionItem) {
    var _a;
    if (expressionItem == undefined)
      return;
    if (expressionItem.paramVariable) {
      return this.proccessVarialbeParameter(expressionItem);
    }
    if (expressionItem.operand !== index.FilterOperand.NULL && expressionItem.operand !== "NOT_NULL") {
      let value = expressionItem.value;
      const type = expressionItem.type;
      /*
       Precisamos validar o expressionItem.userInterface além do expressionItem.type
       pois para filtros herdados do HTML5 não temos o tipo OBJECT, fazendo com que a expressão
       fique inválida para campos do tipo pesquisa.
      */
      if (core.UserInterface.SEARCH === expressionItem.userInterface || expressionItem.userInterface === core.UserInterface.OPTIONSELECTOR || core.DataType.OBJECT == type) {
        value = (_a = value === null || value === void 0 ? void 0 : value.value) !== null && _a !== void 0 ? _a : value;
      }
      if (core.DataType.NUMBER == type && value != undefined) {
        value = core.NumberUtils.stringToNumber(value);
        this.checkIsValidNumber(value);
      }
      else if (core.DataType.DATE == type) {
        value = this.convertDataValue(value);
        if (value === undefined) {
          return;
        }
      }
      else if (core.DataType.BOOLEAN == type) {
        value = value ? "S" : "N";
      }
      return value;
    }
    return expressionItem.operand;
  }
  static checkIsValidNumber(value) {
    if (isNaN(value)) {
      throw new Error('O valor informado não é um número válido.');
    }
  }
  static proccessVarialbeParameter(expressionItem) {
    if (expressionItem.systemConfig != undefined) {
      const systemConfig = expressionItem.systemConfig;
      return `?:{entidade=${systemConfig.entity || ""};campo=${systemConfig.fieldName || ""}}`;
    }
    if (expressionItem.userConfig != undefined) {
      const userConfig = expressionItem.userConfig;
      return `?:{desc=${userConfig.description || ""};tipo=${userConfig.type || ""}}`;
    }
    return `?:{entidade=${expressionItem.entityName || ""};campo=${expressionItem.fieldName || ""}}`;
  }
  static convertDataValue(value) {
    if (value == null || value === '' || value === undefined) {
      return;
    }
    if (typeof value == 'string') {
      const trimmedValue = value.trim();
      if (trimmedValue === '' || trimmedValue === '/' || trimmedValue === '  /  /') {
        return;
      }
      value = new Date(value);
    }
    if (value instanceof Date && isNaN(value.getTime())) {
      return;
    }
    return core.DateUtils.formatDate(value);
  }
  /*
  * Cria uma expressão de filtro para um grupo de itens.
  */
  static buildGroupExpression(expressionGroup) {
    var _a, _b;
    if (!((_a = expressionGroup === null || expressionGroup === void 0 ? void 0 : expressionGroup.items) === null || _a === void 0 ? void 0 : _a.length))
      return "";
    const itemExpressions = expressionGroup.items.map((item) => this.buildFilterExpression(item)).join(` ${expressionGroup.operand} `);
    if (((_b = expressionGroup === null || expressionGroup === void 0 ? void 0 : expressionGroup.childrenGroups) === null || _b === void 0 ? void 0 : _b.length) > 0) {
      const childGroupExpressions = expressionGroup.childrenGroups.map((children) => this.buildGroupExpression(children)).join(` ${expressionGroup.operand} `);
      return `(${itemExpressions} ${expressionGroup.operand} (${childGroupExpressions}))`;
    }
    return `(${itemExpressions})`;
  }
  /*
  * Valida se os campos das expressão estão válidas para serem criada ou editada.
  */
  static validateFields(expressionGroup) {
    const allItems = this.buildPlainExpressionItems(expressionGroup);
    for (const item of allItems) {
      const isValidItem = this.validateExpressionItem(item);
      if (!isValidItem) {
        return false;
      }
    }
    return true;
  }
  static buildPlainExpressionItems(expressionGroup) {
    const { items = [], childrenGroups = [] } = expressionGroup || {};
    const getItemsFromChildren = (childrenGroup) => {
      return childrenGroup.reduce((listAcc, children) => {
        var _a;
        if (children.items)
          listAcc = listAcc.concat(children.items);
        if ((_a = children.childrenGroups) === null || _a === void 0 ? void 0 : _a.length) {
          listAcc = listAcc.concat(getItemsFromChildren(children.childrenGroups));
        }
        return listAcc;
      }, []);
    };
    return items.concat(getItemsFromChildren(childrenGroups));
  }
  static validateExpressionItem(expressionItem) {
    const requiredFields = {
      fieldName: (value) => !!value,
      value: (value, byPassValue) => {
        if (byPassValue)
          return true;
        return value != undefined;
      },
      operand: (value) => !!value
    };
    const isAllValidFields = Object.entries(requiredFields).every(entries => {
      const [fieldName, validate] = entries;
      const byPassValue = expressionItem.paramVariable || expressionItem.userInterface === 'SWITCH' || ["NULL", "NOT_NULL"].includes(expressionItem.operand);
      return validate(expressionItem[fieldName], byPassValue);
    });
    return isAllValidFields;
  }
  static getNormalizedValue(params, value) {
    return params.reduce((arrayValues, currentParam, index) => {
      if (currentParam.dataType === core.DataType.BOOLEAN && (arrayValues == undefined || arrayValues[index] == undefined)) {
        arrayValues = !!arrayValues && !Array.isArray(arrayValues) ? [arrayValues] : arrayValues || [];
        arrayValues[index] = false;
      }
      return arrayValues;
    }, value);
  }
  /*
  * Valida se os filtros personalizados com campo variável são válido.
  */
  static validateVariableValues(config, editorValue) {
    if (!config)
      return true;
    let valuesArray = editorValue || config.value;
    let isValid = true;
    if (config.type === filterItemType_enum.FilterItemType.PERSONALIZED) {
      const activeFilters = (config.groupedItems || []).filter(item => item.visible);
      const allFilterWithVariableParams = activeFilters.filter(activeFilter => { var _a, _b, _c; return !!((_c = (_b = (_a = activeFilter.props) === null || _a === void 0 ? void 0 : _a.personalizedFilter) === null || _b === void 0 ? void 0 : _b.parameters) === null || _c === void 0 ? void 0 : _c.length); });
      const allParamsWithValues = allFilterWithVariableParams.flatMap(filter => { var _a; return (_a = filter.props.personalizedFilter) === null || _a === void 0 ? void 0 : _a.parameters; });
      const valuesFromParams = allFilterWithVariableParams.flatMap((filter) => {
        return filter.props.personalizedFilter.parameters.flatMap((param, index) => {
          if (!filter.value) {
            return null;
          }
          if (filter.value[index] === undefined && param.dataType === core.DataType.BOOLEAN) {
            return false;
          }
          return filter.value[index];
        });
      });
      valuesArray = this.getNormalizedValue(allParamsWithValues, valuesArray);
      isValid = allParamsWithValues.length === valuesFromParams.length && valuesFromParams.every(value => value != null);
    }
    return isValid;
  }
  /*
  * Constroi uma lista parâmetros para todos os itens de grupos e subgrupos que são
  * do tipo variavel;
  */
  static buildVariableParameters(expressionGroup) {
    const allItems = this.buildPlainExpressionItems(expressionGroup);
    const allParams = [];
    for (const item of allItems) {
      if (!item.paramVariable) {
        continue;
      }
      allParams.push({
        entityName: item.entityName,
        fieldName: item.fieldName
      });
    }
    return allParams;
  }
}

exports.PersonalizedFilterUtils = PersonalizedFilterUtils;
