"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.TagsManagementState = exports.TAG_MAX_LENGTH = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _mobx = require("mobx");
var _types = require("@wix/bex-utils/@wix/ambassador-os-tags-v1-tag/types");
var _uuid = require("uuid");
var _events = require("events");
var _CollectionState = require("../CollectionState");
var _CollectionOptimisticActions = require("../CollectionOptimisticActions");
var _TaskState = require("../TaskState");
var _util = require("../../util");
var _services = require("../../services");
var _createTagErrors = require("../../services/tagsService/createTagErrors");
var _tagsService = require("../../services/tagsService");
const TAG_MAX_LENGTH = exports.TAG_MAX_LENGTH = 30;
const MAX_TAGS = 1000;
const TAGS_PAGE_SIZE = 100;

// Pre-cursor tag creation ceiling (restored from before pagination, unrelated to page size)
const LEGACY_MAX_TAGS = 100;
class TagsManagementState {
  constructor(params) {
    var _params$container$int;
    (0, _defineProperty2.default)(this, "collection", void 0);
    (0, _defineProperty2.default)(this, "optimisticActions", void 0);
    (0, _defineProperty2.default)(this, "container", void 0);
    (0, _defineProperty2.default)(this, "fqdn", void 0);
    (0, _defineProperty2.default)(this, "initTask", new _TaskState.TaskState());
    (0, _defineProperty2.default)(this, "tagsService", void 0);
    (0, _defineProperty2.default)(this, "events", new _events.EventEmitter());
    (0, _defineProperty2.default)(this, "overrideShowToast", false);
    (0, _defineProperty2.default)(this, "_resolvedListTagsError", void 0);
    (0, _defineProperty2.default)(this, "shouldAllowTagsPagination", void 0);
    this.container = params.container;
    this.fqdn = params.fqdn;
    this.tagsService = new _tagsService.TagsService({
      container: this.container
    });
    this.shouldAllowTagsPagination = !!((_params$container$int = params.container.internalExperiments) != null && _params$container$int.enabled('specs.cairo.TagsPagination'));
    this.collection = new _CollectionState.CollectionState({
      ...params.container,
      limit: TAGS_PAGE_SIZE,
      events: {
        onError: error => {
          var _this$container$error, _this$container$error2;
          this._resolvedListTagsError = (_this$container$error = (_this$container$error2 = this.container.errorHandler).getResolvedError) == null ? void 0 : _this$container$error.call(_this$container$error2, error.err);
        }
      },
      paginationMode: this.shouldAllowTagsPagination ? 'cursor' : undefined,
      queryName: [this.fqdnString, 'tags'].join('/'),
      fetchData: async ({
        cursor,
        limit,
        search
      }) => {
        if (this.shouldAllowTagsPagination) {
          const result = await this.tagsService.queryTags({
            fqdn: this.fqdnString,
            exposure: _types.TagExposure.PRIVATE,
            query: {
              cursorPaging: {
                limit,
                cursor: cursor ?? undefined
              },
              ...(search ? {
                filter: {
                  name: {
                    $startsWith: search
                  }
                }
              } : {})
            }
          }, {}, {
            serverErrorOverride: () => ({
              message: this.container.translate('cairo.tags.collectionPage.popover.loadTags.error.body'),
              action: {
                text: this.container.translate('cairo.tags.loadTags.error.CTA'),
                onClick: () => this.retry()
              }
            })
          });
          return {
            items: result.items,
            cursor: result.cursor,
            hasNext: result.hasNext
          };
        }
        const fetchedItems = await this.tagsService.listTags({
          fqdn: this.fqdnString,
          exposure: _types.TagExposure.PRIVATE
        }, {}, {
          serverErrorOverride: () => ({
            message: this.container.translate('cairo.tags.collectionPage.popover.loadTags.error.body'),
            action: {
              text: this.container.translate('cairo.tags.loadTags.error.CTA'),
              onClick: () => this.retry()
            }
          })
        });
        return {
          items: fetchedItems,
          total: fetchedItems.length
        };
      },
      itemKey: ({
        id
      }) => id,
      itemName: ({
        name
      }) => name,
      filters: {},
      showToast: toastConfig => {
        var _params$container;
        if (this.overrideShowToast) {
          this.events.emit('showToast', toastConfig);
          return {
            remove: () => {
              this.events.emit('hideToast', toastConfig);
            }
          };
        }
        if (params != null && (_params$container = params.container) != null && _params$container.showToast) {
          return params.container.showToast(toastConfig);
        }
        return {
          remove: () => {}
        };
      }
    });
    this.optimisticActions = new _CollectionOptimisticActions.CollectionOptimisticActions({
      container: this.container,
      collection: this.collection,
      orderBy: ({
        sort
      }) => [...(sort || []), {
        fieldName: ({
          createdDate
        }) => (createdDate ?? new Date()).valueOf(),
        order: 'asc'
      }]
    });
    (0, _mobx.makeObservable)(this, {
      init: _mobx.action,
      createTag: _mobx.action,
      updateTag: _mobx.action,
      deleteTag: _mobx.action,
      retry: _mobx.action
    });
  }
  init() {
    if (!this._isFqdnValid()) {
      return;
    }
    const {
      collection,
      optimisticActions
    } = this;
    const disposers = [collection.init(), optimisticActions.init()];
    this.initTask.runOnce(async () => {
      collection.initTask.runOnce();
      await collection.initTask.status.promise;
    });
    return () => {
      disposers.forEach(disposer => disposer());
    };
  }
  retry() {
    this.collection.initTask.runOnce();
  }
  get items() {
    return this.collection.result.items ?? [];
  }
  get hasMore() {
    return !this.collection.fetchedLastPage;
  }
  async loadMore() {
    await this.collection.fetchNextPageIfNeeded();
  }
  get isError() {
    return this.initTask.status.isError;
  }
  get error() {
    return this._resolvedListTagsError;
  }
  get isLoading() {
    const {
      status
    } = this.collection.initTask;
    return status.isIdle || status.isLoading;
  }
  get isSuccessful() {
    const {
      status
    } = this.collection.initTask;
    return status.isSuccess;
  }
  get fqdnString() {
    return (0, _util.fqdnToString)(this.fqdn);
  }
  getTagById(tagId) {
    var _this$collection$resu;
    return (_this$collection$resu = this.collection.result._keyedItemsMap) == null || (_this$collection$resu = _this$collection$resu.get(tagId)) == null ? void 0 : _this$collection$resu.item;
  }
  getTagNameById(tagId) {
    var _this$getTagById;
    return (_this$getTagById = this.getTagById(tagId)) == null ? void 0 : _this$getTagById.name;
  }
  _isFqdnValid() {
    return this.fqdn.resource !== undefined;
  }
  _optimisticActionBaseParams(optimisticActionParams, {
    tagsBIReporter,
    actionName,
    origin,
    tagName,
    filteredListSize,
    isFromSearch = false,
    errorCode
  }) {
    const {
      onError,
      onTryAgain,
      onUndo,
      ...otherOptimisticActionParams
    } = optimisticActionParams;
    return {
      onError: error => {
        tagsBIReporter.onError({
          tagName,
          actionName,
          origin
        }, error);
        this.container.internalMonitor.reportError({
          error: new _services.WixPatternsError({
            errorCode,
            originalException: error
          }),
          category: 'Tags'
        });
        onError == null || onError(error);
      },
      onTryAgain: () => {
        tagsBIReporter.onTryAgain({
          actionName,
          isFromSearch,
          filteredListSize
        });
        onTryAgain == null || onTryAgain();
      },
      onUndo: () => {
        tagsBIReporter.onUndo({
          actionName
        });
        onUndo == null || onUndo();
      },
      ...otherOptimisticActionParams
    };
  }
  get tagsLimit() {
    return this.shouldAllowTagsPagination ? MAX_TAGS : LEGACY_MAX_TAGS;
  }
  hasReachedTagsLimit() {
    return !this.hasMore && this.items.length >= this.tagsLimit;
  }
  showTagsLimitErrorToast(visualType) {
    const excessCount = Math.max(1, this.items.length - this.tagsLimit + 1);
    this.collection.showToast({
      message: (0, _createTagErrors.getTagsReachedLimitErrorMessage)({
        visualType,
        translate: this.container.translate,
        excessCount,
        limit: this.tagsLimit
      }),
      biName: 'cairo-max-tags-error',
      type: 'ERROR'
    });
  }
  async createTag(params) {
    const {
      name,
      origin,
      tagSubOrigin,
      filteredListSize,
      id = (0, _uuid.v4)(),
      isFromSearch = false,
      onSuccess,
      optimisticActionParams = {},
      tagsBIReporter,
      visualType = 'toast'
    } = params;
    const actionName = 'Add tag';
    tagsBIReporter.onAction({
      tagName: name,
      isFromSearch,
      actionName,
      origin,
      tagSubOrigin
    });
    if (this.hasReachedTagsLimit()) {
      return this.showTagsLimitErrorToast(visualType);
    }
    const newTag = {
      id,
      name,
      fqdn: this.fqdnString,
      exposure: _types.TagExposure.PRIVATE,
      createdDate: new Date()
    };
    this.optimisticActions.createOne(newTag, {
      submit: async () => {
        const serverCreatedTag = await this.tagsService.createTag({
          tag: newTag
        }, (0, _createTagErrors.createTagErrors)({
          translate: this.container.translate,
          visualType,
          retryFn: () => this.createTag(params),
          excessCount: Math.max(1, this.items.length - this.tagsLimit + 1),
          limit: this.tagsLimit
        }));
        await (onSuccess == null ? void 0 : onSuccess(serverCreatedTag));
        if (this.shouldAllowTagsPagination) {
          // intentional fire-and-forget: optimistic state is already applied
          void this.collection.refreshAllPages();
        }
        return [serverCreatedTag];
      },
      ...this._optimisticActionBaseParams(optimisticActionParams, {
        tagsBIReporter,
        actionName,
        origin,
        filteredListSize,
        tagName: name,
        isFromSearch,
        errorCode: 'CreateTagFailed'
      })
    });
  }
  async updateTag({
    tagToUpdate,
    previousName,
    origin,
    tagSubOrigin,
    filteredListSize,
    isFromSearch = false,
    optimisticActionParams = {},
    tagsBIReporter
  }) {
    const actionName = 'Rename tag';
    tagsBIReporter.onAction({
      actionName,
      previousName,
      tagName: tagToUpdate.name,
      isFromSearch,
      origin,
      tagSubOrigin
    });
    this.optimisticActions.updateOne({
      ...tagToUpdate,
      revision: (+tagToUpdate.revision + 1).toString()
    }, {
      submit: async () => {
        const updatedTag = await this.tagsService.updateTag({
          tag: tagToUpdate
        });
        if (this.shouldAllowTagsPagination) {
          // intentional fire-and-forget: optimistic state is already applied
          void this.collection.refreshAllPages();
        }
        return updatedTag;
      },
      ...this._optimisticActionBaseParams(optimisticActionParams, {
        tagsBIReporter,
        actionName,
        origin,
        filteredListSize,
        tagName: previousName,
        isFromSearch,
        errorCode: 'UpdateTagFailed'
      })
    });
  }
  async deleteTag({
    tagToDelete,
    origin,
    tagSubOrigin,
    filteredListSize,
    isFromSearch = true,
    optimisticActionParams = {},
    tagsBIReporter
  }) {
    const tagName = tagToDelete.name;
    const actionName = 'Delete tag';
    tagsBIReporter.onAction({
      actionName,
      tagName,
      isFromSearch,
      origin,
      tagSubOrigin
    });
    await this.optimisticActions.deleteOne(tagToDelete, {
      submit: async () => {
        const result = await this.tagsService.deleteTag({
          tagId: tagToDelete.id
        });
        if (this.shouldAllowTagsPagination) {
          // intentional fire-and-forget: optimistic state is already applied
          void this.collection.refreshAllPages();
        }
        return result;
      },
      ...this._optimisticActionBaseParams(optimisticActionParams, {
        tagsBIReporter,
        actionName,
        origin,
        tagName,
        filteredListSize,
        isFromSearch,
        errorCode: 'RemoveTagFailed'
      })
    });
  }
}
exports.TagsManagementState = TagsManagementState;
//# sourceMappingURL=TagsManagementState.js.map