import { AdaptableModuleBase } from './AdaptableModuleBase';
import * as ModuleConstants from '../Utilities/Constants/ModuleConstants';
import { TEAMSHARING_GET, TEAMSHARING_IMPORT_ITEM, TEAMSHARING_LINK_ITEM, TEAMSHARING_PROCESS_IMPORT, TEAMSHARING_REMOVE_ITEM, TEAMSHARING_SET, TEAMSHARING_SHARE, TEAMSHARING_UPDATE_ITEM, TeamSharingUpdateItem, } from '../Redux/ActionsReducers/TeamSharingRedux';
import * as TeamSharingRedux from '../Redux/ActionsReducers/TeamSharingRedux';
import isEqual from 'lodash/isEqual';
import { LAYOUT_SAVE } from '../Redux/ActionsReducers/LayoutRedux';
import { getSharedEntityStaleDepsItemView, SharedEntityTypeItemView, getSharedEntityActiveStatusObjectView, } from '../View/TeamSharing/SharedEntityObjectView';
import { TeamSharingApplyButton } from '../View/TeamSharing/TeamSharingApplyButton';
import { SharedEntityDependencies } from '../View/TeamSharing/SharedEntityDependencies';
import ArrayExtensions from '../Utilities/Extensions/ArrayExtensions';
import flatten from 'lodash/flatten';
import AdaptableHelper from '../Utilities/Helpers/AdaptableHelper';
export class TeamSharingModule extends AdaptableModuleBase {
    constructor(api) {
        super(ModuleConstants.TeamSharingModuleId, ModuleConstants.TeamSharingFriendlyName, 'folder-shared', 'TeamSharingPopup', 'Team Sharing allows users to share - at run-time - Adaptable Objects between colleagues.', api);
        this.SKIP_TEAMSHARING_UPDATE_ACTIONS = [
            TEAMSHARING_GET,
            TEAMSHARING_SET,
            TEAMSHARING_SHARE,
            TEAMSHARING_IMPORT_ITEM,
            TEAMSHARING_PROCESS_IMPORT,
            TEAMSHARING_REMOVE_ITEM,
            TEAMSHARING_LINK_ITEM,
            TEAMSHARING_UPDATE_ITEM,
        ];
    }
    onAdaptableReady() {
        // make sure there is no zombie import process remaining (in case a previous import crashed)
        this.api.internalApi.dispatchReduxAction(TeamSharingRedux.TeamSharingCommitImport());
        if (this.api.teamSharingApi.isTeamSharingAvailable()) {
            this.api.teamSharingApi.refreshTeamSharing();
        }
        this.api.eventApi.on('AdaptableStateChanged', (adaptableStateChangedInfo) => this.handleStateChanged(adaptableStateChangedInfo));
    }
    isModuleAvailable() {
        return super.isModuleAvailable() && this.api.teamSharingApi.isTeamSharingAvailable();
    }
    isModuleObjectsShareable() {
        return false;
    }
    getPopupMaxWidth() {
        return 1000;
    }
    handleStateChanged(adaptableStateChangedInfo) {
        // check if TeamSharing is activated
        if (!this.api.teamSharingApi.isTeamSharingAvailable()) {
            return;
        }
        // skip all teamsharing actions, otherwise we could get in an infinite loop
        if (this.SKIP_TEAMSHARING_UPDATE_ACTIONS.includes(adaptableStateChangedInfo.action.type)) {
            return;
        }
        // check if there is any changed adaptable object
        const changedAdaptableObject = this.extractAdaptableObjectFromAction(adaptableStateChangedInfo.action);
        if (!changedAdaptableObject) {
            return;
        }
        // check if the changed adaptable object is active in TeamSharing
        const activeSharedEntity = this.api.internalApi.getState().TeamSharing.ActiveSharedEntityMap[changedAdaptableObject.Uuid];
        if (!activeSharedEntity) {
            return;
        }
        // handle special case of LAYOUT_SAVE which might be called redundantly without actually changing the state
        const isLayoutStateUnchanged = adaptableStateChangedInfo.action.type === LAYOUT_SAVE &&
            isEqual(adaptableStateChangedInfo.oldState.Layout, adaptableStateChangedInfo.newState.Layout);
        if (isLayoutStateUnchanged) {
            return;
        }
        this.api.internalApi.dispatchReduxAction(TeamSharingUpdateItem(changedAdaptableObject, adaptableStateChangedInfo.userName));
    }
    extractAdaptableObjectFromAction(action) {
        // this implementation is based on the assumption that any action which mutates an AdaptableObject has
        // at most one(1) property which has an 'Uuid:TypeUuid' defined (and that is the AdaptableObject, of course)
        if (!action) {
            return;
        }
        return Object.values(action).find((actionPropertyValue) => AdaptableHelper.isAdaptableObject(actionPropertyValue));
    }
    isAdaptableObjectPresentInLocalState(sharedEntity) {
        return !!this.api.internalApi
            .getModuleService()
            .getModuleById(sharedEntity.Module)
            ?.getModuleAdaptableObjects()
            .find((adaptableObject) => adaptableObject.Uuid === sharedEntity.Entity.Uuid);
    }
    isSharedEntityADependency(sharedEntity) {
        const allSharedEntries = this.api.teamSharingApi.getLoadedAdaptableSharedEntities();
        return allSharedEntries.some((sharedEntryCandidate) => {
            return sharedEntryCandidate?.EntityDependencyIds?.includes(sharedEntity.Uuid);
        });
    }
    isStaleAndActive(sharedEntity) {
        const staleActiveEntities = this.api.internalApi
            .getTeamSharingService()
            .getStaleActiveSharedEntities();
        return (this.isAdaptableObjectPresentInLocalState(sharedEntity) &&
            !!staleActiveEntities[sharedEntity.Uuid]);
    }
    getDependencies(sharedEntity) {
        if (!Array.isArray(sharedEntity.EntityDependencyIds) ||
            sharedEntity.EntityDependencyIds.length === 0) {
            return [sharedEntity];
        }
        const allSharedEntities = this.api.teamSharingApi.getLoadedAdaptableSharedEntities();
        const dependencies = sharedEntity.EntityDependencyIds.map((dependencyUuid) => allSharedEntities.find((entity) => entity.Uuid === dependencyUuid));
        return flatten(dependencies.map((dependency) => this.getDependencies(dependency)));
    }
    getStaleDependencies(sharedEntity) {
        return this.getDependencies(sharedEntity).filter((dependency) => dependency.Uuid !== sharedEntity.Uuid && this.isStaleAndActive(dependency));
    }
    toView(sharedEntity) {
        const isDependency = this.isSharedEntityADependency(sharedEntity);
        const staleDependencies = this.getStaleDependencies(sharedEntity);
        const staleDependenciesViewItems = [];
        if (staleDependencies?.length) {
            staleDependenciesViewItems.push({
                name: 'Stale Deps',
                view: getSharedEntityStaleDepsItemView(staleDependencies),
            });
        }
        const sharedViewItems = [];
        const isStaleAndActive = this.isStaleAndActive(sharedEntity);
        if (!isDependency || isStaleAndActive) {
            sharedViewItems.push({
                name: 'Shared',
                view: getSharedEntityActiveStatusObjectView(isDependency),
            });
        }
        return {
            items: [
                !isDependency &&
                    sharedEntity.Description && {
                    name: 'Name',
                    values: [sharedEntity.Description],
                },
                !isDependency && {
                    name: 'Share Mode',
                    values: [sharedEntity.Type],
                },
                ...sharedViewItems,
                {
                    name: 'Type',
                    view: SharedEntityTypeItemView,
                },
                ...staleDependenciesViewItems,
                ArrayExtensions.IsNotNullOrEmpty(sharedEntity.EntityDependencyIds) && {
                    name: 'Dependencies',
                    isLabelInline: true,
                    view: SharedEntityDependencies,
                },
            ].filter(Boolean),
            abObject: sharedEntity,
        };
    }
    toViewAll() {
        return ((this.api.teamSharingApi.getLoadedAdaptableSharedEntities() ?? [])
            // only top level
            .filter((sharedEntity) => !this.isSharedEntityADependency(sharedEntity))
            .map((item) => this.toView(item)));
    }
    getViewProperties() {
        return {
            actions: [TeamSharingApplyButton],
            onMount: () => {
                this.api.teamSharingApi.refreshTeamSharing();
            },
            getDeleteAction: (sharedEntity) => {
                return TeamSharingRedux.TeamSharingRemoveItem(sharedEntity.Uuid);
            },
            emptyView: 'Shared Items will appear here when available.',
        };
    }
}
