import { ApplicationContext, DateUtils, ErrorException, ObjectUtils, StringUtils, WarningException } from "@sankhyalabs/core";
import { RefreshType } from "./enum/RefreshType";
import { ParamType } from "./enum/ParamType";
import { DataFetcher } from "../../../lib";
import { ActionsType } from "./enum/ActionsType";
import { getSelectedRecordsIDsInfo } from "../../../lib/utils/GetSelectedRecordsIDsInfo";
const MASTER_ROW_PROPERTY = "__MASTER_ROW__";
const ENTITY_NAME_PROPERTY = '__ENTITY_NAME__';
const SERVICE_GET_CONFIGURATIONS = 'SystemUtilsSP.getConf';
export default class Actions {
  constructor(actionsExecuteInterface, dataUnit, appResourceId) {
    var _a;
    this._lastValuesCache = {};
    this._actionsExecuteInterface = actionsExecuteInterface;
    this._dataUnit = dataUnit;
    this._selectedRows = ((_a = dataUnit === null || dataUnit === void 0 ? void 0 : dataUnit.getSelectionInfo()) === null || _a === void 0 ? void 0 : _a.isAllRecords()) ? [] : dataUnit === null || dataUnit === void 0 ? void 0 : dataUnit.getSelectionInfo().records;
    this._application = ApplicationContext.getContextValue("__SNK__APPLICATION__");
    this._appResourceId = appResourceId;
  }
  getPrimaryKeys() {
    const ids = getSelectedRecordsIDsInfo(this._dataUnit);
    return ids.map(({ name }) => name);
  }
  apply(action, hasParamsToSave) {
    this._application.closePopUp();
    this._actionsExecuteInterface.execute(action, this._dataUnit)
      .then(({ execSource, callback }) => {
      this.resolvePromptParams(action, execSource, hasParamsToSave)
        .then(() => {
        this.actionExecute(execSource, callback);
      });
    });
  }
  ;
  async execute(action) {
    var _a;
    if (!action.actionConfig) {
      throw new WarningException(this._application.messagesBuilder.getMessage("snkActionsButton.title.warning", undefined), this._application.messagesBuilder.getMessage("snkActionsButton.action.incorrectAction", { description: action.description }));
    }
    if (!!((_a = action.actionConfig.params) === null || _a === void 0 ? void 0 : _a.promptParam)) {
      const paramsSource = action.actionConfig.params.promptParam;
      let hasParamsToSave = false;
      for (let i = 0; i < paramsSource.length; i++) {
        let paramSource = paramsSource[i];
        if (!hasParamsToSave && paramSource.saveLast === 'true') {
          hasParamsToSave = true;
          break;
        }
      }
      if (hasParamsToSave) {
        action.actionConfig.params.promptParam = await this.loadSavedValuesIntoParams(action);
      }
      const form = document.createElement("snk-actions-form");
      window.document.body.appendChild(form);
      form.action = ObjectUtils.copy(action);
      form.applyParameters = (resultAction) => {
        this.apply(resultAction, hasParamsToSave);
      };
      form.openPopup();
    }
    else if (action.type != ActionsType.LAUNCH_SCREEN) {
      this._actionsExecuteInterface.execute(action, this._dataUnit)
        .then(({ execSource, callback }) => {
        this.actionExecute(execSource, callback);
      });
    }
    else {
      this._actionsExecuteInterface.execute(action, this._dataUnit);
    }
  }
  loadSavedValuesIntoParams(action) {
    return this.loadLastValues(action)
      .then((lastParams) => {
      let resultParams = action.actionConfig.params.promptParam;
      if (lastParams) {
        lastParams.param.forEach(lastParam => {
          resultParams = resultParams.map((param) => {
            if (param.name !== lastParam.paramName)
              return param;
            if (param.paramType === 'B') {
              return Object.assign(Object.assign({}, param), { value: lastParam.$ === 'S' });
            }
            return Object.assign(Object.assign({}, param), { value: lastParam.$ });
          });
        });
      }
      return resultParams;
    });
  }
  async actionExecute(execSource, callback) {
    execSource.virtualPage = this.buildVirtualPage();
    await this.prepareAndExecute(execSource, callback);
    this.recordsReloader(execSource.refreshType);
  }
  resolvePromptParams(action, execSource, hasParamsToSave) {
    return new Promise(resolve => {
      const paramsSource = action.actionConfig.params.promptParam;
      let params = [];
      paramsSource.forEach(paramSource => {
        params.push(this.buildPromptParam(paramSource));
      });
      this.putParamsOnExecSource(params, execSource);
      if (hasParamsToSave) {
        this.saveLastValues(action, params);
      }
      resolve();
    });
  }
  buildPromptParam(param) {
    let type = param.paramType;
    let isCheckbox = false;
    let fieldProps;
    let entityPK;
    let value = param.value;
    switch (type) {
      case ParamType.DATE:
        type = 'D';
        break;
      case ParamType.DATETIME:
        type = 'H';
        break;
      case ParamType.DECIMAL:
        type = 'F';
        fieldProps = {
          'sk-precision': Number(param.precision)
        };
        break;
      case ParamType.BOOLEAN:
        type = 'S';
        isCheckbox = true;
        value = param.value ? 'S' : 'N';
        break;
      case ParamType.ENTITY:
        fieldProps = {
          'sk-entity-name': param.entityName,
          'sk-allow-show-hierarchical-mode': param.hierarchyEntity,
          'sk-data-type': 'S'
        };
        if (param.hierarchyEntity && param.entityPK) {
          entityPK = param.entityPK;
        }
        value = param.value ? Number(param.value) : null;
        break;
      case ParamType.OPTIONS:
        type = 'O';
        let options = param.options.split(';').map(function (opc, index) {
          let data;
          let value;
          if (opc.indexOf('=') > -1) {
            let opcArr = opc.split('=');
            data = opcArr[0];
            value = opcArr[1];
          }
          else {
            data = (index + 1);
            value = opc;
          }
          return {
            data: data,
            value: value
          };
        });
        fieldProps = {
          'sk-options': options
        };
        break;
    }
    return {
      description: param.label,
      required: param.required == 'true',
      fieldName: param.name,
      fieldNameOri: param.name,
      entityPK: entityPK,
      paramType: param.paramType,
      type: type,
      isCheckbox: isCheckbox,
      saveLast: param.saveLast,
      fieldProp: fieldProps,
      value: value,
      isGeneratedName: param.isGeneratedName
    };
  }
  putParamsOnExecSource(params, execSource) {
    execSource.params = {
      param: []
    };
    params.forEach(param => {
      if (param.isGeneratedName && param.value) {
        throw new ErrorException(this._application.messagesBuilder.getMessage("snkActionsButton.title.error", undefined), this._application.messagesBuilder.getMessage("snkActionsButton.action.emptyParamName", undefined));
      }
      if (!StringUtils.isEmpty(param.value)) {
        execSource.params.param.push({
          type: this.getParamDataType(param.paramType),
          paramName: param.fieldName,
          $: this.getParamValue(param)
        });
      }
    });
  }
  getParamDataType(type) {
    let dataType;
    switch (type) {
      case "D":
        dataType = "F";
        break;
      case "DT":
      case "DH":
        dataType = "D";
        break;
      case "B":
      case "ENTITY":
      case "SO":
        dataType = "S";
        break;
      default:
        dataType = type;
    }
    return dataType;
  }
  getParamValue(param) {
    let value = param.value;
    if (!value) {
      return value;
    }
    if (param.paramType == 'DT') {
      value = DateUtils.formatDate(value);
    }
    else if (param.paramType == 'DH') {
      value = DateUtils.formatDateTime(value);
    }
    return value;
  }
  async loadLastValues(action) {
    const resourceId = await this.buildResourceId(action.actionID);
    return new Promise((resolve, reject) => {
      if (this._lastValuesCache[resourceId]) {
        resolve(this._lastValuesCache[resourceId]);
      }
      else {
        const config = {
          config: {
            chave: resourceId,
            tipo: 'T'
          }
        };
        DataFetcher.get().callServiceBroker(SERVICE_GET_CONFIGURATIONS, config)
          .then((result) => {
          var _a, _b;
          let lastParams;
          if ((_b = (_a = result.config) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.params) {
            lastParams = result.config.data.params;
            if (!Array.isArray(lastParams.param)) {
              lastParams.param = [lastParams.param];
            }
          }
          this._lastValuesCache[resourceId] = lastParams;
          resolve(lastParams);
        }).catch((error) => {
          reject(error);
        });
      }
    });
  }
  async saveLastValues(action, params) {
    if (this._application) {
      let config = {
        params: {
          param: []
        }
      };
      params.forEach(param => {
        if (param.saveLast == 'true') {
          config.params.param.push({
            paramName: param.fieldName,
            $: param.value
          });
        }
      });
      const resourceId = await this.buildResourceId(action.actionID);
      this._lastValuesCache[resourceId] = config.params;
      this._application.saveConfig(resourceId, config);
    }
  }
  async buildResourceId(actionId) {
    return this._appResourceId + '.actionconfig.' + actionId;
  }
  async prepareAndExecute(execSource, executeAction) {
    this.addRows(execSource);
    await executeAction(execSource);
  }
  addRows(execSource) {
    const primaryKeys = this.getPrimaryKeys();
    const rows = {
      row: []
    };
    const sourceRows = this._selectedRows;
    for (const i in sourceRows) {
      const sourceRow = sourceRows[i];
      const row = {};
      if (sourceRow.hasOwnProperty(MASTER_ROW_PROPERTY)) {
        row.master = 'S';
        row.entityName = sourceRow.__ENTITY_NAME__;
        delete sourceRow[MASTER_ROW_PROPERTY];
        delete sourceRow[ENTITY_NAME_PROPERTY];
      }
      if (!row.field) {
        row.field = [];
      }
      for (const primaryKey of primaryKeys) {
        row.field.push({
          fieldName: primaryKey,
          $: sourceRow[primaryKey]
        });
      }
      rows.row.push(row);
    }
    if (rows.row.length > 0) {
      execSource.rows = rows;
    }
  }
  recordsReloader(refreshType) {
    switch (refreshType) {
      case RefreshType.NONE:
        break;
      case RefreshType.PARENT:
      case RefreshType.MASTER:
      case RefreshType.ALL:
        this._dataUnit.loadData();
        break;
      default:
        this._dataUnit.reloadCurrentRecord();
    }
  }
  ;
  buildVirtualPage() {
    var _a, _b, _c, _d;
    if ((_b = (_a = this._dataUnit) === null || _a === void 0 ? void 0 : _a.getSelectionInfo()) === null || _b === void 0 ? void 0 : _b.isAllRecords()) {
      const virtualPage = {
        filters: { filters: (_c = this._dataUnit) === null || _c === void 0 ? void 0 : _c.getAppliedFilters() },
        orders: { orders: (_d = this._dataUnit) === null || _d === void 0 ? void 0 : _d.getSort() },
      };
      return virtualPage;
    }
  }
}
