import { DataUnit } from "@sankhyalabs/core";
import { ArrayRepository } from "./ArrayRepository";
import { ColumnFilterManager } from "@sankhyalabs/ezui/dist/collection/components/ez-grid/utils";
import SortingUtils from "@sankhyalabs/core/dist/utils/SortingUtils";
export default class PreloadManager {
  static setLoadingStatus(dataUnit, loadingInProgress) {
    this._loadingStatus.set(dataUnit.name, loadingInProgress);
  }
  static isCacheEnabled(_dataUnit) {
    return true;
  }
  static cacheRecords(dataUnit, records, resetDatabase, loadingInProgress) {
    PreloadManager.setLoadingStatus(dataUnit, loadingInProgress);
    if (PreloadManager.isCacheEnabled(dataUnit)) {
      this.getRepository(dataUnit).push(records);
    }
    else {
      if (resetDatabase) {
        this._repositories.delete(dataUnit.name);
      }
    }
  }
  static getSortingFunction(dataUnit, sorting) {
    return SortingUtils.getSortingFunction(dataUnit, sorting);
  }
  static async getDistinct(dataUnit, fieldName, onlyLabel = false) {
    if (!PreloadManager.isCacheEnabled(dataUnit)) {
      return Promise.resolve(ColumnFilterManager.compileDistinct(fieldName, dataUnit));
    }
    let filterFunction;
    const request = dataUnit.getLastLoadRequest();
    if (request != undefined) {
      const columnFilters = ColumnFilterManager.getColumnFilters(request.filters, fieldName);
      filterFunction = ColumnFilterManager.getFilterFunction(dataUnit, Array.from(columnFilters.values()));
    }
    if (onlyLabel) {
      return Promise.resolve(this.compileDistinctByLabel(dataUnit, fieldName, filterFunction));
    }
    return new Promise((accept, reject) => {
      PreloadManager.getRepository(dataUnit).distict(record => {
        if (filterFunction != undefined && !filterFunction(record)) {
          return undefined;
        }
        const fieldValue = record[fieldName];
        if (fieldValue == undefined) {
          return { key: null, value: null };
        }
        let value = fieldValue.value != undefined ? fieldValue.value : fieldValue;
        return { key: dataUnit.getFormattedValue(fieldName, fieldValue), value };
      })
        .then(result => {
        if (result == undefined) {
          accept(undefined);
          return;
        }
        accept(Array.from(result.entries()).map(([label, value]) => ({ label, value, check: true })));
      })
        .catch(reason => reject(reason));
    });
  }
  static compileDistinctByLabel(dataUnit, fieldName, filterFunction) {
    const groupedOptions = new Map();
    const cachedRecords = PreloadManager.getRepository(dataUnit).getFromCache();
    cachedRecords.forEach(record => {
      if (filterFunction != undefined && !filterFunction(record)) {
        return;
      }
      const fieldValue = record[fieldName];
      if (fieldValue == undefined) {
        const nullKey = '';
        if (!groupedOptions.has(nullKey)) {
          groupedOptions.set(nullKey, {
            values: new Set([null]),
            option: { label: null, value: null, check: true },
          });
        }
        return;
      }
      const value = fieldValue.value != undefined ? fieldValue.value : fieldValue;
      const label = (fieldValue === null || fieldValue === void 0 ? void 0 : fieldValue.label) ? fieldValue.label : dataUnit.getFormattedValue(fieldName, fieldValue);
      const key = String(label !== null && label !== void 0 ? label : '');
      let grouped = groupedOptions.get(key);
      if (!grouped) {
        grouped = {
          values: new Set(),
          option: { label, value, check: true },
        };
        groupedOptions.set(key, grouped);
      }
      grouped.values.add(value);
    });
    return Array.from(groupedOptions.values()).map(grouped => {
      const option = grouped.option;
      option.__multiValues = Array.from(grouped.values.values());
      return grouped.option;
    });
  }
  static async loadData(dataUnit, request, loadFromServer) {
    try {
      if (PreloadManager.isCacheEnabled(dataUnit)) {
        const useCache = [
          "EZ_GRID_LOADING_SOURCE",
          DataUnit.CHANGING_PAGE_LOADING_SOURCE,
          DataUnit.ALL_RECORDS_SELECTION_SOURCE
        ].includes(request.source);
        if (useCache) {
          const isCacheEmpty = await PreloadManager.getRepository(dataUnit).isEmpty();
          if (!isCacheEmpty) {
            return PreloadManager.loadFromCache(dataUnit, request);
          }
        }
        //Como não vamos aproveitar o cache, ele precisa ser limpo.
        PreloadManager.getRepository(dataUnit).clear().catch(() => { });
      }
      return loadFromServer(dataUnit, request);
    }
    catch (error) {
      console.error(error);
      return Promise.reject(error);
    }
  }
  static insertRecords(dataUnit, reference, records) {
    if (PreloadManager.isCacheEnabled(dataUnit)) {
      PreloadManager.getRepository(dataUnit).insert(reference, records);
    }
  }
  static updateRecords(dataUnit, records) {
    if (PreloadManager.isCacheEnabled(dataUnit)) {
      PreloadManager.getRepository(dataUnit).update(records);
    }
  }
  static removeRecords(dataUnit, records) {
    if (PreloadManager.isCacheEnabled(dataUnit)) {
      PreloadManager.getRepository(dataUnit).delete(records);
    }
  }
  static async countRecords(dataUnit) {
    if (PreloadManager.isCacheEnabled(dataUnit)) {
      return PreloadManager.getRepository(dataUnit).count();
    }
    return Promise.resolve(0);
  }
  static getRepository(dataUnit) {
    const name = dataUnit.name;
    if (!PreloadManager._repositories.has(name)) {
      PreloadManager._repositories.set(name, new ArrayRepository((recordA, recordB) => recordA.__record__id__ === recordB.__record__id__));
    }
    return PreloadManager._repositories.get(name);
  }
  static async loadFromCache(dataUnit, request) {
    return new Promise((accept, reject) => {
      const columnFilters = ColumnFilterManager.getColumnFilters(request.filters, "");
      const { limit, offset, sort } = request;
      PreloadManager.getRepository(dataUnit)
        .load(ColumnFilterManager.getFilterFunction(dataUnit, Array.from(columnFilters.values())), PreloadManager.getSortingFunction(dataUnit, sort), offset, limit)
        .then(loadResult => {
        const stillLoading = PreloadManager._loadingStatus.get(dataUnit.name);
        const { count, result: records } = loadResult;
        const firstRecord = count == 0 ? 0 : offset + 1;
        const lastRecord = offset + Math.min(records.length, limit);
        const currentPage = offset / limit;
        const paginationInfo = {
          count, currentPage, firstRecord, lastRecord,
          hasMore: stillLoading || (lastRecord < count),
          total: stillLoading ? undefined : count
        };
        accept({ records, paginationInfo });
      })
        .catch(reason => reject(reason));
    });
  }
  static getCachedRecords(dataUnit) {
    return PreloadManager.getRepository(dataUnit).getFromCache();
  }
}
PreloadManager._repositories = new Map();
PreloadManager._loadingStatus = new Map();
