/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { action, computed, flow, flowResult, makeObservable, observable, } from 'mobx';
import { assertErrorThrown, LogEvent, NetworkClientError, HttpStatus, guaranteeNonNullable, assertTrue, ActionState, prettyCONSTName, } from '@finos/legend-shared';
import { EDITOR_MODE, ACTIVITY_MODE } from './EditorConfig.js';
import { extractEntityNameFromPath } from '@finos/legend-storage';
import { Workflow, Project, Revision, RevisionAlias, Version, Workspace, WorkspaceAccessType, Patch, AuthorizableProjectAction, isProjectSandbox, } from '@finos/legend-server-sdlc';
import { LEGEND_STUDIO_APP_EVENT } from '../../__lib__/LegendStudioEvent.js';
export const entityDiffSorter = (a, b) => extractEntityNameFromPath(a.newPath ?? a.oldPath ?? '').localeCompare(extractEntityNameFromPath(b.newPath ?? b.oldPath ?? ''));
export class EditorSDLCState {
    editorStore;
    fetchPublishedProjectVersionsState = ActionState.create();
    isWorkspaceOutdated = false;
    isCheckingIfWorkspaceIsOutdated = false;
    isFetchingProjectVersions = false;
    isFetchingProject = false;
    currentProject;
    currentPatch;
    currentWorkspace;
    remoteWorkspaceRevision;
    currentRevision;
    workspaceWorkflows = [];
    projectVersions = [];
    projectPublishedVersions = [];
    authorizedActions;
    constructor(editorStore) {
        makeObservable(this, {
            currentProject: observable,
            currentPatch: observable,
            currentWorkspace: observable,
            remoteWorkspaceRevision: observable,
            currentRevision: observable,
            isWorkspaceOutdated: observable,
            workspaceWorkflows: observable,
            projectVersions: observable,
            isCheckingIfWorkspaceIsOutdated: observable,
            isFetchingProjectVersions: observable,
            isFetchingProject: observable,
            projectPublishedVersions: observable,
            authorizedActions: observable,
            activeProject: computed,
            activeWorkspace: computed,
            activeRevision: computed,
            activePatch: computed,
            activeRemoteWorkspaceRevision: computed,
            canCreateWorkspace: computed,
            canCreateVersion: computed,
            isWorkspaceOutOfSync: computed,
            isActiveProjectSandbox: computed,
            setCurrentProject: action,
            setCurrentPatch: action,
            setCurrentWorkspace: action,
            setCurrentRevision: action,
            setWorkspaceLatestRevision: action,
            fetchCurrentProject: flow,
            fetchCurrentWorkspace: flow,
            fetchProjectVersions: flow,
            checkIfCurrentWorkspaceIsInConflictResolutionMode: flow,
            fetchRemoteWorkspaceRevision: flow,
            fetchCurrentRevision: flow,
            fetchCurrentPatch: flow,
            checkIfWorkspaceIsOutdated: flow,
            buildWorkspaceLatestRevisionEntityHashesIndex: flow,
            buildWorkspaceBaseRevisionEntityHashesIndex: flow,
            buildProjectLatestRevisionEntityHashesIndex: flow,
            fetchWorkspaceWorkflows: flow,
            fetchPublishedProjectVersions: flow,
            fetchAuthorizedActions: flow,
        });
        this.editorStore = editorStore;
    }
    get activeProject() {
        return guaranteeNonNullable(this.currentProject, `Active project has not been properly set`);
    }
    get isActiveProjectSandbox() {
        return Boolean(this.currentProject && isProjectSandbox(this.currentProject));
    }
    get activeWorkspace() {
        return guaranteeNonNullable(this.currentWorkspace, `Active workspace has not been properly set`);
    }
    get activePatch() {
        return this.currentPatch;
    }
    get activeRevision() {
        return guaranteeNonNullable(this.currentRevision, `Active revision has not been properly set`);
    }
    get activeRemoteWorkspaceRevision() {
        return guaranteeNonNullable(this.remoteWorkspaceRevision, `Active workspace latest revision has not been properly set`);
    }
    get isWorkspaceOutOfSync() {
        return this.activeRemoteWorkspaceRevision.id !== this.activeRevision.id;
    }
    get canCreateWorkspace() {
        return this.userCanPerformAction(AuthorizableProjectAction.CREATE_WORKSPACE);
    }
    get canCreateVersion() {
        return this.userCanPerformAction(AuthorizableProjectAction.CREATE_VERSION);
    }
    unAuthorizedActionMessage(_action) {
        return `Your are not entitled to perform the action: ${prettyCONSTName(_action)}`;
    }
    userCanPerformAction(authorizedAction) {
        return Boolean(this.authorizedActions === undefined ||
            this.authorizedActions.includes(authorizedAction));
    }
    setCurrentProject(val) {
        this.currentProject = val;
    }
    setCurrentPatch(val) {
        this.currentPatch = val;
    }
    setCurrentWorkspace(val) {
        this.currentWorkspace = val;
    }
    setCurrentRevision(val) {
        this.currentRevision = val;
    }
    setWorkspaceLatestRevision(val) {
        this.remoteWorkspaceRevision = val;
    }
    handleChangeDetectionRefreshIssue(error) {
        if (!this.currentProject ||
            !this.currentWorkspace ||
            (error instanceof NetworkClientError &&
                error.response.status === HttpStatus.NOT_FOUND)) {
            this.editorStore.applicationStore.alertService.setBlockingAlert({
                message: 'Current project or workspace no longer exists',
                prompt: 'Please refresh the application',
            });
        }
        else {
            this.editorStore.applicationStore.alertService.setBlockingAlert({
                message: error.message,
            });
        }
    }
    *fetchCurrentProject(projectId, options) {
        try {
            this.isFetchingProject = true;
            this.currentProject = Project.serialization.fromJson((yield this.editorStore.sdlcServerClient.getProject(projectId)));
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            if (!options?.suppressNotification) {
                this.editorStore.applicationStore.notificationService.notifyError(error);
            }
        }
        finally {
            this.isFetchingProject = false;
        }
    }
    *fetchCurrentPatch(projectId, patchReleaseVersionId, options) {
        if (patchReleaseVersionId) {
            try {
                this.currentPatch = Patch.serialization.fromJson((yield this.editorStore.sdlcServerClient.getPatch(projectId, patchReleaseVersionId)));
            }
            catch (error) {
                assertErrorThrown(error);
                this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
                if (!options?.suppressNotification) {
                    this.editorStore.applicationStore.notificationService.notifyError(error);
                }
            }
        }
    }
    *fetchCurrentWorkspace(projectId, patchReleaseVersionId, workspaceId, workspaceType, options) {
        try {
            this.currentWorkspace = Workspace.serialization.fromJson((yield this.editorStore.sdlcServerClient.getWorkspace(projectId, patchReleaseVersionId, workspaceId, workspaceType)));
            this.currentWorkspace.source = patchReleaseVersionId;
            const isInConflictResolutionMode = (yield flowResult(this.checkIfCurrentWorkspaceIsInConflictResolutionMode()));
            if (isInConflictResolutionMode) {
                this.editorStore.setMode(EDITOR_MODE.CONFLICT_RESOLUTION);
                this.currentWorkspace.accessType =
                    WorkspaceAccessType.CONFLICT_RESOLUTION;
                this.editorStore.setActiveActivity(ACTIVITY_MODE.CONFLICT_RESOLUTION);
            }
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            if (!options?.suppressNotification) {
                this.editorStore.applicationStore.notificationService.notifyError(error);
            }
        }
    }
    *fetchProjectVersions() {
        try {
            this.isFetchingProjectVersions = true;
            this.projectVersions = (yield this.editorStore.sdlcServerClient.getVersions(this.activeProject.projectId)).map((v) => Version.serialization.fromJson(v));
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
        }
        finally {
            this.isFetchingProjectVersions = false;
        }
    }
    *checkIfCurrentWorkspaceIsInConflictResolutionMode() {
        return (yield this.editorStore.sdlcServerClient.checkIfWorkspaceIsInConflictResolutionMode(this.activeProject.projectId, this.activeWorkspace));
    }
    *fetchRemoteWorkspaceRevision(projectId, workspace) {
        try {
            this.editorStore.localChangesState.workspaceSyncState.setIncomingRevisions([]);
            const latestRevision = Revision.serialization.fromJson(this.editorStore.isInConflictResolutionMode
                ? (yield this.editorStore.sdlcServerClient.getConflictResolutionRevision(projectId, workspace, RevisionAlias.CURRENT))
                : (yield this.editorStore.sdlcServerClient.getRevision(projectId, workspace, RevisionAlias.CURRENT)));
            this.setWorkspaceLatestRevision(latestRevision);
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
    }
    *fetchCurrentRevision(projectId, workspace) {
        try {
            const currentRevision = Revision.serialization.fromJson(this.editorStore.isInConflictResolutionMode
                ? (yield this.editorStore.sdlcServerClient.getConflictResolutionRevision(projectId, workspace, RevisionAlias.CURRENT))
                : (yield this.editorStore.sdlcServerClient.getRevision(projectId, workspace, RevisionAlias.CURRENT)));
            this.setCurrentRevision(currentRevision);
            this.setWorkspaceLatestRevision(currentRevision);
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
    }
    *checkIfWorkspaceIsOutdated() {
        try {
            this.isCheckingIfWorkspaceIsOutdated = true;
            this.isWorkspaceOutdated = this.editorStore.isInConflictResolutionMode
                ? (yield this.editorStore.sdlcServerClient.isConflictResolutionOutdated(this.activeProject.projectId, this.activeWorkspace))
                : (yield this.editorStore.sdlcServerClient.isWorkspaceOutdated(this.activeProject.projectId, this.activeWorkspace));
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
        finally {
            this.isCheckingIfWorkspaceIsOutdated = false;
        }
    }
    *buildWorkspaceLatestRevisionEntityHashesIndex() {
        try {
            let entities = [];
            if (!this.editorStore.isInConflictResolutionMode) {
                // fetch latest revision
                // NOTE: this check is already covered in conflict resolution mode so we don't need to do it here
                const latestRevision = Revision.serialization.fromJson((yield this.editorStore.sdlcServerClient.getRevision(this.activeProject.projectId, this.activeWorkspace, RevisionAlias.CURRENT)));
                // make sure there is no good recovery from this, at this point all users work risk conflict
                assertTrue(latestRevision.id === this.activeRevision.id, `Can't run local change detection: current workspace revision is not the latest. Please backup your work and refresh the application`);
                entities =
                    (yield this.editorStore.sdlcServerClient.getEntitiesByRevision(this.activeProject.projectId, this.activeWorkspace, this.activeRevision.id));
            }
            else {
                entities =
                    (yield this.editorStore.sdlcServerClient.getEntitiesByRevision(this.activeProject.projectId, this.activeWorkspace, RevisionAlias.CURRENT));
            }
            this.editorStore.changeDetectionState.workspaceLocalLatestRevisionState.setEntities(entities);
            yield flowResult(this.editorStore.changeDetectionState.workspaceLocalLatestRevisionState.buildEntityHashesIndex(entities, LogEvent.create(LEGEND_STUDIO_APP_EVENT.CHANGE_DETECTION_BUILD_LOCAL_HASHES_INDEX__SUCCESS)));
            this.editorStore.tabManagerState.refreshCurrentEntityDiffViewer();
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
    }
    *buildWorkspaceBaseRevisionEntityHashesIndex() {
        try {
            const workspaceBaseEntities = (yield this.editorStore.sdlcServerClient.getEntitiesByRevision(this.activeProject.projectId, this.activeWorkspace, RevisionAlias.BASE));
            this.editorStore.changeDetectionState.workspaceBaseRevisionState.setEntities(workspaceBaseEntities);
            yield flowResult(this.editorStore.changeDetectionState.workspaceBaseRevisionState.buildEntityHashesIndex(workspaceBaseEntities, LogEvent.create(LEGEND_STUDIO_APP_EVENT.CHANGE_DETECTION_BUILD_WORKSPACE_HASHES_INDEX__SUCCESS)));
            this.editorStore.tabManagerState.refreshCurrentEntityDiffViewer();
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
    }
    *buildProjectLatestRevisionEntityHashesIndex() {
        try {
            const projectLatestEntities = (yield this.editorStore.sdlcServerClient.getEntities(this.activeProject.projectId, undefined));
            this.editorStore.changeDetectionState.projectLatestRevisionState.setEntities(projectLatestEntities);
            yield flowResult(this.editorStore.changeDetectionState.projectLatestRevisionState.buildEntityHashesIndex(projectLatestEntities, LogEvent.create(LEGEND_STUDIO_APP_EVENT.CHANGE_DETECTION_BUILD_PROJECT_LATEST_HASHES_INDEX__SUCCESS)));
            this.editorStore.tabManagerState.refreshCurrentEntityDiffViewer();
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
    }
    *fetchWorkspaceWorkflows() {
        try {
            this.workspaceWorkflows = (yield this.editorStore.sdlcServerClient.getWorkflowsByRevision(this.activeProject.projectId, this.activeWorkspace, RevisionAlias.CURRENT)).map((v) => Workflow.serialization.fromJson(v));
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
    }
    *fetchAuthorizedActions() {
        try {
            const authorizedActions = (yield this.editorStore.sdlcServerClient.getAutorizedActions(this.activeProject.projectId));
            this.authorizedActions = authorizedActions;
        }
        catch (error) {
            assertErrorThrown(error);
            // if there is an error fetching authorized actions we should set undefined
            this.authorizedActions = undefined;
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
        }
    }
    *fetchPublishedProjectVersions() {
        try {
            this.fetchPublishedProjectVersionsState.inProgress();
            this.projectPublishedVersions =
                (yield this.editorStore.depotServerClient.getVersions(this.editorStore.projectConfigurationEditorState
                    .currentProjectConfiguration.groupId, this.editorStore.projectConfigurationEditorState
                    .currentProjectConfiguration.artifactId, true));
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.DEPOT_MANAGER_FAILURE), error);
        }
        finally {
            this.fetchPublishedProjectVersionsState.complete();
        }
    }
}
//# sourceMappingURL=EditorSDLCState.js.map