"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.ImportState = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _mobx = require("mobx");
var _model = require("../../model");
var _ConditionalModalState = require("../ConditionalModalState");
var _parseCsv = require("./parseCsv");
var _set = _interopRequireDefault(require("lodash/set"));
const DEFAULT_BATCH_SIZE = 100;
function normalize(value) {
  return value.trim().toLowerCase();
}
function toMappedRows(rows, headers, mappingByHeader) {
  return rows.map(row => {
    const mapped = {};
    headers.forEach((header, index) => {
      const mappedField = mappingByHeader[header];
      if (mappedField == null) {
        return;
      }
      (0, _set.default)(mapped, mappedField, row[index] ?? '');
    });
    return mapped;
  });
}
class ImportState {
  constructor(props) {
    (0, _defineProperty2.default)(this, "fields", void 0);
    (0, _defineProperty2.default)(this, "bulkUploadItems", void 0);
    (0, _defineProperty2.default)(this, "backup", void 0);
    (0, _defineProperty2.default)(this, "collection", void 0);
    (0, _defineProperty2.default)(this, "importModalState", void 0);
    (0, _defineProperty2.default)(this, "translate", void 0);
    (0, _defineProperty2.default)(this, "errorHandler", void 0);
    (0, _defineProperty2.default)(this, "showToast", void 0);
    (0, _defineProperty2.default)(this, "batchSize", void 0);
    (0, _defineProperty2.default)(this, "discardChangesModal", new _ConditionalModalState.ConditionalModalState());
    (0, _defineProperty2.default)(this, "currentStep", 'upload');
    (0, _defineProperty2.default)(this, "importStatus", {
      ..._model.queryStatus.idle
    });
    (0, _defineProperty2.default)(this, "parseError", null);
    (0, _defineProperty2.default)(this, "fileName", '');
    (0, _defineProperty2.default)(this, "csvHeaders", []);
    (0, _defineProperty2.default)(this, "csvRows", []);
    (0, _defineProperty2.default)(this, "mappingByHeader", {});
    (0, _defineProperty2.default)(this, "processedCount", 0);
    (0, _defineProperty2.default)(this, "totalCount", 0);
    (0, _defineProperty2.default)(this, "result", {
      succeeded: 0,
      failed: 0,
      errors: []
    });
    (0, _defineProperty2.default)(this, "isBackingUp", false);
    (0, _defineProperty2.default)(this, "isRestoring", false);
    (0, _defineProperty2.default)(this, "restoreFn", null);
    (0, _defineProperty2.default)(this, "_cancelled", false);
    (0, _defineProperty2.default)(this, "_abortController", null);
    this.fields = props.fields ?? [];
    this.bulkUploadItems = props.bulkUploadItems;
    this.backup = props.backup;
    this.collection = props.collection;
    this.importModalState = props.importModalState;
    this.translate = props.translate;
    this.errorHandler = props.errorHandler;
    this.showToast = props.showToast;
    this.batchSize = props.batchSize ?? DEFAULT_BATCH_SIZE;
    (0, _mobx.makeObservable)(this, {
      currentStep: _mobx.observable.ref,
      importStatus: _mobx.observable.ref,
      parseError: _mobx.observable.ref,
      fileName: _mobx.observable.ref,
      csvHeaders: _mobx.observable.ref,
      csvRows: _mobx.observable.ref,
      mappingByHeader: _mobx.observable.ref,
      processedCount: _mobx.observable.ref,
      totalCount: _mobx.observable.ref,
      result: _mobx.observable.ref,
      isBackingUp: _mobx.observable.ref,
      isRestoring: _mobx.observable.ref,
      hasParsedRows: _mobx.computed,
      hasMappings: _mobx.computed,
      selectedFieldIds: _mobx.computed,
      mappedRows: _mobx.computed,
      onUploadContinue: _mobx.action.bound,
      goToUpload: _mobx.action.bound,
      setMapping: _mobx.action.bound,
      close: _mobx.action.bound,
      onFileSelected: _mobx.action.bound,
      startImport: _mobx.action.bound,
      reset: _mobx.action.bound
    });
  }
  init() {
    return () => undefined;
  }
  get hasParsedRows() {
    return this.csvHeaders.length > 0 && this.csvRows.length > 0;
  }
  get hasMappings() {
    return Object.values(this.mappingByHeader).some(value => value != null);
  }
  get selectedFieldIds() {
    return new Set(Object.values(this.mappingByHeader).filter(v => v != null));
  }
  get mappedRows() {
    return toMappedRows(this.csvRows, this.csvHeaders, this.mappingByHeader);
  }
  reset() {
    var _this$_abortControlle;
    (_this$_abortControlle = this._abortController) == null || _this$_abortControlle.abort();
    this._abortController = null;
    this.currentStep = 'upload';
    this.importStatus = {
      ..._model.queryStatus.idle
    };
    this.parseError = null;
    this.fileName = '';
    this.csvHeaders = [];
    this.csvRows = [];
    this.mappingByHeader = {};
    this.processedCount = 0;
    this.totalCount = 0;
    this.result = {
      succeeded: 0,
      failed: 0,
      errors: []
    };
    this.isBackingUp = false;
    this.isRestoring = false;
    this.restoreFn = null;
    this._cancelled = false;
  }
  async close() {
    if (this.currentStep === 'progress') {
      var _this$_abortControlle2;
      this._cancelled = true;
      (_this$_abortControlle2 = this._abortController) == null || _this$_abortControlle2.abort();
      if (!this.isBackingUp) {
        await this._restoreBackup();
      }
      this.collection.clearResultAndMoveToStart({
        force: true
      });
    }
    this.importModalState.close();
  }
  async _restoreBackup() {
    const restoreFn = this.restoreFn;
    if (!restoreFn) {
      return;
    }
    const restoreController = new AbortController();
    this._abortController = restoreController;
    this.isRestoring = true;
    try {
      await restoreFn(restoreController.signal);
    } catch (error) {
      console.error('Restore failed', error);
    }
    (0, _mobx.runInAction)(() => {
      this.isRestoring = false;
      this.restoreFn = null;
    });
  }
  goToUpload() {
    this.currentStep = 'upload';
  }
  async discardAndGoBack() {
    this.discardChangesModal.open('goBack');
    const {
      result
    } = await this.discardChangesModal.modal.promise();
    if (result === 'confirmed') {
      this.goToUpload();
    }
  }
  async discardAndClose() {
    this.discardChangesModal.open('close');
    const {
      result
    } = await this.discardChangesModal.modal.promise();
    if (result === 'confirmed') {
      this.close();
    }
  }
  onUploadContinue() {
    if (this.hasParsedRows) {
      this.currentStep = 'configuration';
    }
  }
  getDefaultMapping(headers) {
    const mapping = {};
    const fields = this.fields.map(field => ({
      id: field.id ?? '',
      header: field.header ?? ''
    }));
    headers.forEach(header => {
      const normalizedHeader = normalize(header);
      const matched = fields.find(field => normalize(field.id) === normalizedHeader || normalize(field.header) === normalizedHeader);
      mapping[header] = (matched == null ? void 0 : matched.id) || null;
    });
    return mapping;
  }
  applyParsedCsv(fileName, parsedCsv) {
    this.fileName = fileName;
    this.parseError = null;
    this.csvHeaders = parsedCsv.headers;
    this.csvRows = parsedCsv.rows;
    this.mappingByHeader = this.getDefaultMapping(parsedCsv.headers);
    this.currentStep = 'configuration';
  }
  async onFileSelected(file) {
    if (file == null) {
      return;
    }
    try {
      const content = await file.text();
      const parsedCsv = (0, _parseCsv.parseCsv)(content);
      if ('message' in parsedCsv) {
        (0, _mobx.runInAction)(() => {
          this.parseError = parsedCsv.message;
          this.fileName = file.name;
          this.csvHeaders = [];
          this.csvRows = [];
          this.mappingByHeader = {};
          this.currentStep = 'upload';
        });
        return;
      }
      (0, _mobx.runInAction)(() => {
        this.applyParsedCsv(file.name, parsedCsv);
      });
    } catch (e) {
      console.error(e);
      (0, _mobx.runInAction)(() => {
        this.parseError = this.translate('cairo.import.parseFailed');
        this.currentStep = 'upload';
      });
    }
  }
  setMapping(header, fieldId) {
    this.mappingByHeader = {
      ...this.mappingByHeader,
      [header]: fieldId
    };
  }
  async _uploadBatches(batches) {
    let processedRows = 0;
    for (const batch of batches) {
      if (this._cancelled) {
        break;
      }
      try {
        const batchResult = await this.bulkUploadItems(batch);
        this.result = {
          succeeded: this.result.succeeded + batchResult.succeeded,
          failed: this.result.failed + batchResult.failed,
          errors: [...this.result.errors, ...batchResult.errors]
        };
      } catch (error) {
        this.result = {
          succeeded: this.result.succeeded,
          failed: this.result.failed + batch.length,
          errors: this.result.errors
        };
        break;
      }
      processedRows += batch.length;
      (0, _mobx.runInAction)(() => {
        this.processedCount = Math.min(processedRows, this.totalCount);
      });
    }
    return this.result;
  }
  async _runBackup() {
    const backup = this.backup;
    if (!backup) {
      return false;
    }
    try {
      const result = await backup(this._abortController.signal);
      if (this._cancelled) {
        return true;
      }
      if (result != null && result.restore) {
        this.restoreFn = result.restore;
      }
    } catch (error) {
      if (this._cancelled) {
        return true;
      }
      (0, _mobx.runInAction)(() => {
        this.isBackingUp = false;
        this.importStatus = {
          ..._model.queryStatus.error,
          error
        };
      });
      return true;
    }
    (0, _mobx.runInAction)(() => {
      this.isBackingUp = false;
    });
    return false;
  }
  _createRowsBatches(rows) {
    return rows.reduce((acc, row, index) => {
      if (index % this.batchSize === 0) {
        acc.push([]);
      }
      acc[acc.length - 1].push(row);
      return acc;
    }, []);
  }
  async startImport() {
    if (!this.hasMappings) {
      return;
    }
    this._cancelled = false;
    this._abortController = new AbortController();
    const rows = this.mappedRows;
    const totalCount = rows.length;
    const batches = this._createRowsBatches(rows);
    (0, _mobx.runInAction)(() => {
      this.currentStep = 'progress';
      this.totalCount = totalCount;
      this.processedCount = 0;
      this.isBackingUp = !!this.backup;
    });
    const backupFailed = await this._runBackup();
    if (backupFailed) {
      return;
    }
    const promise = this._uploadBatches(batches);
    this.importStatus = {
      ..._model.queryStatus.loading,
      promise
    };
    try {
      await promise;
      (0, _mobx.runInAction)(() => {
        if (this._cancelled) {
          return;
        }
        this.importStatus = {
          ..._model.queryStatus.success,
          data: this.result
        };
        if (this.result.failed === 0) {
          this.importModalState.close();
          this.collection.clearResultAndMoveToStart({
            force: true
          });
        }
      });
    } catch (error) {
      (0, _mobx.runInAction)(() => {
        this.importStatus = {
          ..._model.queryStatus.error,
          error
        };
      });
    }
  }
}
exports.ImportState = ImportState;
//# sourceMappingURL=ImportState.js.map