import { action, makeObservable, computed, observable } from 'mobx';
import { CollectionOptimisticActions, TAG_MAX_LENGTH, TagsBIReporter, } from '@wix/bex-core';
import { cairoFiltersPanelUsed } from '@wix/bex-core/bi';
import { v4 as uuid } from 'uuid';
import { TagsBulkAssignButtonState } from './TagsBulkAssignButtonState';
import { TagsBulkAssignAsyncState } from './TagsBulkAssignAsyncState';
import { TagsBulkAssignSyncState } from './TagsBulkAssignSyncState';
const origin = 'bulk_assign_popover';
export class TagsBulkAssignPopoverState {
    constructor({ tagsManagementState, collectionState, tagsModalState, bulkUpdateTags, asyncBulkUpdateTags, getTags, assignButtonConfig, }) {
        this.initialSelectedIds = [];
        this.initialIndeterminateTagIds = [];
        this.indeterminateTagIds = [];
        this.assignedTagIds = [];
        this.optimisticNewTag = null;
        this.isShown = false;
        this.searchValue = '';
        this.triggerButtonRef = null;
        this.assignTag = async ({ tag }) => {
            this.optimisticNewTag = null;
            if (this.assignedTagIds.includes(tag.id)) {
                return;
            }
            this.assignedTagIds.push(tag.id);
        };
        this.assignTagOptimistic = (tagName, tagId = 'fake tag id') => {
            this.optimisticNewTag = {
                id: tagId,
                name: tagName,
                createdDate: new Date(),
            };
        };
        this.unassignTag = async ({ tag }) => {
            const updatedAssignedTagIds = this.assignedTagIds.filter((assignedTagId) => assignedTagId !== tag.id);
            this.assignedTagIds = updatedAssignedTagIds;
        };
        this._calcTagsCount = (selectedKeyedItems) => {
            const tagsCount = this.tagsManagementState.items.reduce((result, tag) => {
                result[tag.id] = 0;
                return result;
            }, {});
            selectedKeyedItems.forEach((selectedKeyedItem) => {
                const tags = selectedKeyedItem.item.tags ??
                    this.getTags?.(selectedKeyedItem.item);
                const entityTagIds = tags?.privateTags?.tagIds || [];
                [...new Set(entityTagIds)].forEach((entityTagId) => {
                    if (entityTagId in tagsCount) {
                        tagsCount[entityTagId]++;
                    }
                });
            });
            return tagsCount;
        };
        this._getSelectedTagsIdsStatus = (tagsCount, selectedKeyedItems) => {
            const selectedTagIds = [];
            const indeterminateTagIds = [];
            for (const [tagId, tagCount] of Object.entries(tagsCount)) {
                if (tagCount === selectedKeyedItems.length) {
                    selectedTagIds.push(tagId);
                }
                else if (tagCount > 0) {
                    indeterminateTagIds.push(tagId);
                }
            }
            return { selectedTagIds, indeterminateTagIds };
        };
        this._isInitialUnassignedTag = (tag) => !this.initialIndeterminateTagIds.includes(tag.id) &&
            !this.initialSelectedIds.includes(tag.id);
        this.tagsManagementState = tagsManagementState;
        this.collectionState = collectionState;
        this.optimisticActions =
            collectionState._optimisticActions ??
                new CollectionOptimisticActions({
                    container: this.tagsManagementState.container,
                    collection: this.collectionState,
                });
        this.tagsBIReporter = new TagsBIReporter({
            collection: this.tagsManagementState.collection,
            reportBi: this.tagsManagementState.container.createBILogger({
                componentType: 'TagsBulkAssignPopover',
                ...tagsManagementState.fqdn,
            }),
            location: 'Bulk assign tags popover',
        });
        this.tagsModalState = tagsModalState;
        this.container = tagsManagementState.container;
        this.getTags = getTags;
        this.assignButtonConfig = assignButtonConfig;
        this.bulkAssignSyncState = new TagsBulkAssignSyncState({
            collectionState,
            optimisticActions: this.optimisticActions,
            container: this.container,
            tagsBIReporter: this.tagsBIReporter,
            getTags,
            bulkUpdateTags,
        });
        this.bulkAssignAsyncState = new TagsBulkAssignAsyncState({
            collectionState,
            optimisticActions: this.optimisticActions,
            container: this.container,
            tagsBIReporter: this.tagsBIReporter,
            asyncBulkUpdateTags,
        });
        this.tagsBulkAssignButtonState = new TagsBulkAssignButtonState();
        makeObservable(this, {
            init: action,
            isShown: observable,
            initialSelectedIds: observable,
            initialIndeterminateTagIds: observable,
            indeterminateTagIds: observable,
            searchValue: observable,
            showPopover: action,
            closePopover: action,
            applyChanges: action,
            handleManageTagsCtaClick: action,
            handleItemSelect: action,
            handleSearchChange: action,
            createAndAssignTag: action,
            retry: action,
            assignedTagIds: observable,
            optimisticNewTag: observable.ref,
            assignedTags: computed,
        });
    }
    init() {
        const disposers = [
            this.optimisticActions.init(),
            this.bulkAssignAsyncState.init(),
        ];
        return () => {
            disposers.forEach((disposer) => disposer());
        };
    }
    async showPopover() {
        if (this.isShown) {
            return;
        }
        this.isShown = true;
        this._reportPopoverShowChangedBi(true);
        const { selectedTagIds, indeterminateTagIds } = this._initSelectionState();
        this.initialSelectedIds = selectedTagIds;
        this.assignedTagIds = selectedTagIds;
        this.initialIndeterminateTagIds = indeterminateTagIds;
        this.indeterminateTagIds = indeterminateTagIds;
    }
    closePopover() {
        this._reportPopoverShowChangedBi(false);
        this._reportSearchEventsBi('blur');
        this.isShown = false;
        this.assignedTagIds = [];
        this.initialSelectedIds = [];
        this.initialIndeterminateTagIds = [];
        this.indeterminateTagIds = [];
        requestAnimationFrame(() => {
            const el = this.triggerButtonRef?.current;
            if (el &&
                document.contains(el) &&
                !el.disabled &&
                el.getAttribute('aria-disabled') !== 'true') {
                el.focus();
            }
        });
    }
    async createAndAssignTag(name) {
        this._reportSearchEventsBi('add');
        const tagName = name.slice(0, TAG_MAX_LENGTH);
        const id = uuid();
        this.assignTagOptimistic(tagName, id);
        this.tagsManagementState.createTag({
            name,
            id,
            filteredListSize: 0,
            origin,
            isFromSearch: true,
            tagsBIReporter: this.tagsBIReporter,
            onSuccess: (newTag) => this.assignTag({ tag: newTag }),
            optimisticActionParams: {
                successToast: {
                    biName: 'cairo-save-new-tag-success',
                    message: this.container.translate('cairo.tags.popover.tagCreated.toast.success'),
                },
                errorToast: (error) => {
                    const resolvedError = this.container.errorHandler.getResolvedError?.(error);
                    return {
                        biName: 'cairo-save-new-tag-error',
                        message: resolvedError?.message ??
                            this.container.translate('cairo.tags.collectionPage.toast.create.error'),
                        action: resolvedError?.action,
                    };
                },
            },
        });
    }
    async applyChanges() {
        const { searchValue, newAssignedTagIds, newUnassignedTagIds } = this;
        const params = {
            searchValue,
            newAssignedTagIds,
            newUnassignedTagIds,
        };
        if (this.bulkAssignSyncState.canUseBulkSync) {
            this.bulkAssignSyncState.applyChanges(params);
        }
        else {
            await this.bulkAssignAsyncState.applyChanges(params);
        }
        this.closePopover();
    }
    handleManageTagsCtaClick() {
        this.closePopover();
        this.tagsModalState.openManageTagsModal({
            origin,
            tagSubOrigin: 'bulkAssignPopover',
        });
    }
    handleItemSelect(itemId) {
        const currentTag = this.tagsManagementState.items.find((tag) => tag.id === itemId);
        if (!currentTag) {
            return;
        }
        this._reportSearchEventsBi('select');
        if (this.initialIndeterminateTagIds.includes(itemId) &&
            this.indeterminateTagIds.includes(itemId)) {
            this.indeterminateTagIds = this.indeterminateTagIds.filter((indeterminateTagId) => indeterminateTagId !== itemId);
        }
        if (this.assignedWithOptimisticTagIds.includes(itemId)) {
            this.unassignTag({ tag: currentTag });
        }
        else {
            this.assignTag({ tag: currentTag });
        }
    }
    handleSearchChange(searchValue) {
        this._reportSearchChangedBi(searchValue);
        this.searchValue = searchValue;
    }
    retry() {
        this.tagsManagementState.retry();
    }
    get isInEmptyState() {
        return (this.tagsManagementState.isSuccessful &&
            this.tagsManagementState.items.length === 0);
    }
    get tagOptions() {
        return this.tagsManagementState.items.sort((tag1, tag2) => {
            const isTag1InitialUnassigned = this._isInitialUnassignedTag(tag1);
            const isTag2InitialUnassigned = this._isInitialUnassignedTag(tag2);
            // Showing first assigned/indeterminate tags, and unassigned tags below it
            if (!isTag1InitialUnassigned && isTag2InitialUnassigned) {
                return -1;
            }
            if (isTag1InitialUnassigned && !isTag2InitialUnassigned) {
                return 1;
            }
            // Sub order by showing first newer tags
            return (new Date(tag2.createdDate).valueOf() -
                new Date(tag1.createdDate).valueOf());
        });
    }
    get assignedTags() {
        const savedAssignedTags = this.assignedTagIds
            .map((tagId) => {
            return this.tagsManagementState.items.find((tag) => tag.id === tagId);
        })
            .filter((element) => Boolean(element));
        return this.optimisticNewTag
            ? [...savedAssignedTags, this.optimisticNewTag]
            : savedAssignedTags;
    }
    get assignedWithOptimisticTagIds() {
        return this.assignedTags.map((tag) => tag.id);
    }
    get newAssignedTagIds() {
        return this.assignedTagIds.filter((tagId) => !this.initialSelectedIds.includes(tagId));
    }
    get newUnassignedTagIds() {
        return [
            ...this.initialSelectedIds.filter((tagId) => !this.assignedTagIds.includes(tagId)),
            ...this.initialIndeterminateTagIds.filter((tagId) => ![...this.assignedTagIds, ...this.indeterminateTagIds].includes(tagId)),
        ];
    }
    get canUseBulkUpdate() {
        // Cannot invoke bulk assign while applying async changes
        if (this.bulkAssignAsyncState.isDuringApplyChanges) {
            return false;
        }
        // can use sync
        if (this.bulkAssignSyncState.canUseBulkSync) {
            return true;
        }
        // can use async
        return this.bulkAssignAsyncState.canBulkAssignAsync;
    }
    get isError() {
        return this.tagsManagementState.isError;
    }
    get error() {
        return this.tagsManagementState.error;
    }
    get isLoading() {
        return this.tagsManagementState.isLoading;
    }
    get isDirty() {
        return (this.newAssignedTagIds.length > 0 || this.newUnassignedTagIds.length > 0);
    }
    _initSelectionState() {
        const { selectedKeyedItems } = this.collectionState.bulkSelect;
        const tagsCount = this._calcTagsCount(selectedKeyedItems);
        return this._getSelectedTagsIdsStatus(tagsCount, selectedKeyedItems);
    }
    _reportPopoverShowChangedBi(isOpened) {
        this.tagsBIReporter.reportBi(cairoFiltersPanelUsed({
            isOpened,
            feature: 'Tags',
            origin: 'Assign Tags',
        }));
    }
    _reportSearchChangedBi(searchValue) {
        if (searchValue !== '') {
            this.tagsBIReporter.onSearch(searchValue);
        }
        else {
            this.tagsBIReporter._clearAllEvents();
        }
    }
    _reportSearchEventsBi(event) {
        return this.tagsBIReporter.events.emit(event);
    }
}
//# sourceMappingURL=TagsBulkAssignPopoverState.js.map