/**
 * 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, makeObservable, flowResult, observable, flow, computed, } from 'mobx';
import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
import { LegendStudioUserDataHelper } from '../../../__lib__/LegendStudioUserDataHelper.js';
import { LogEvent, assertErrorThrown, assertNonNullable, guaranteeNonNullable, } from '@finos/legend-shared';
import { EntityDiffViewState } from '../editor-state/entity-diff-editor-state/EntityDiffViewState.js';
import { SPECIAL_REVISION_ALIAS } from '../editor-state/entity-diff-editor-state/EntityDiffEditorState.js';
import { generateSetupRoute } from '../../../__lib__/LegendStudioNavigation.js';
import { EntityDiff, Review, ReviewState, RevisionAlias, AuthorizableProjectAction, isProjectSandbox, } from '@finos/legend-server-sdlc';
import { ActionAlertActionType } from '@finos/legend-application';
export class WorkspaceReviewState {
    editorStore;
    sdlcState;
    reviewTitle = '';
    committedReviewsBetweenWorkspaceBaseAndProjectLatest = [];
    workspaceReview;
    isUpdatingWorkspace = false;
    isRefreshingWorkspaceUpdater = false;
    isFetchingCurrentWorkspaceReview = false;
    isRefreshingWorkspaceChangesDetector = false;
    isClosingWorkspaceReview = false;
    isCreatingWorkspaceReview = false;
    isCommittingWorkspaceReview = false;
    isRecreatingWorkspaceAfterCommittingReview = false;
    constructor(editorStore, sdlcState) {
        makeObservable(this, {
            reviewTitle: observable,
            committedReviewsBetweenWorkspaceBaseAndProjectLatest: observable,
            workspaceReview: observable,
            isUpdatingWorkspace: observable,
            isRefreshingWorkspaceUpdater: observable,
            isFetchingCurrentWorkspaceReview: observable,
            isRefreshingWorkspaceChangesDetector: observable,
            isClosingWorkspaceReview: observable,
            isCreatingWorkspaceReview: observable,
            isCommittingWorkspaceReview: observable,
            isRecreatingWorkspaceAfterCommittingReview: observable,
            canCreateReview: computed,
            canMergeReview: computed,
            setReviewTitle: action,
            openReviewChange: action,
            refreshWorkspaceChanges: flow,
            fetchCurrentWorkspaceReview: flow,
            recreateWorkspaceAfterCommittingReview: flow,
            closeWorkspaceReview: flow,
            createWorkspaceReview: flow,
            commitWorkspaceReview: flow,
        });
        this.editorStore = editorStore;
        this.sdlcState = sdlcState;
    }
    get canCreateReview() {
        return this.sdlcState.userCanPerformAction(AuthorizableProjectAction.SUBMIT_REVIEW);
    }
    get canMergeReview() {
        return this.sdlcState.userCanPerformAction(AuthorizableProjectAction.COMMIT_REVIEW);
    }
    setReviewTitle(val) {
        this.reviewTitle = val;
    }
    openReviewChange(diff) {
        const fromEntityGetter = (entityPath) => entityPath
            ? this.editorStore.changeDetectionState.workspaceBaseRevisionState.entities.find((e) => e.path === entityPath)
            : undefined;
        const toEntityGetter = (entityPath) => entityPath
            ? this.editorStore.changeDetectionState.workspaceLocalLatestRevisionState.entities.find((e) => e.path === entityPath)
            : undefined;
        const fromEntity = EntityDiff.shouldOldEntityExist(diff)
            ? guaranteeNonNullable(fromEntityGetter(diff.getValidatedOldPath()), `Can't find entity with path  '${diff.oldPath}'`)
            : undefined;
        const toEntity = EntityDiff.shouldNewEntityExist(diff)
            ? guaranteeNonNullable(toEntityGetter(diff.getValidatedNewPath()), `Can't find entity with path  '${diff.newPath}'`)
            : undefined;
        this.editorStore.tabManagerState.openTab(new EntityDiffViewState(this.editorStore, SPECIAL_REVISION_ALIAS.WORKSPACE_BASE, SPECIAL_REVISION_ALIAS.WORKSPACE_HEAD, diff.oldPath, diff.newPath, fromEntity, toEntity, fromEntityGetter, toEntityGetter));
    }
    *refreshWorkspaceChanges() {
        const startTime = Date.now();
        this.isRefreshingWorkspaceChangesDetector = true;
        try {
            // ======= (RE)START CHANGE DETECTION =======
            this.editorStore.changeDetectionState.stop();
            yield Promise.all([
                this.sdlcState.buildWorkspaceLatestRevisionEntityHashesIndex(),
                this.sdlcState.buildWorkspaceBaseRevisionEntityHashesIndex(),
            ]);
            this.editorStore.changeDetectionState.start();
            yield Promise.all([
                this.editorStore.changeDetectionState.computeAggregatedProjectLatestChanges(true),
                this.editorStore.changeDetectionState.computeAggregatedWorkspaceChanges(true),
            ]);
            this.editorStore.applicationStore.logService.info(LogEvent.create(LEGEND_STUDIO_APP_EVENT.CHANGE_DETECTION_RESTART__SUCCESS), Date.now() - startTime, 'ms');
            // ======= FINISHED (RE)START CHANGE DETECTION =======
        }
        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);
            this.sdlcState.handleChangeDetectionRefreshIssue(error);
        }
        finally {
            this.isRefreshingWorkspaceChangesDetector = false;
        }
    }
    *fetchCurrentWorkspaceReview() {
        try {
            this.isFetchingCurrentWorkspaceReview = true;
            const currentWorkspaceRevision = (yield this.editorStore.sdlcServerClient.getRevision(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, RevisionAlias.CURRENT));
            const reviews = (yield this.editorStore.sdlcServerClient.getReviews(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, {
                state: ReviewState.OPEN,
                revisionIds: [
                    currentWorkspaceRevision.id,
                    currentWorkspaceRevision.id,
                ],
                limit: 1,
            }));
            const review = reviews.find((r) => r.workspaceId === this.sdlcState.activeWorkspace.workspaceId &&
                r.workspaceType === this.sdlcState.activeWorkspace.workspaceType);
            if (reviews.length) {
                try {
                    assertNonNullable(review, `Opened review associated with HEAD revision '${currentWorkspaceRevision.id}' of workspace '${this.sdlcState.activeWorkspace.workspaceType}' found, but the retrieved review does not belong to the workspace`);
                }
                catch (error) {
                    assertErrorThrown(error);
                    this.editorStore.applicationStore.notificationService.notifyWarning(error.message);
                }
            }
            this.workspaceReview = review
                ? Review.serialization.fromJson(review)
                : undefined;
        }
        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);
            this.sdlcState.handleChangeDetectionRefreshIssue(error);
        }
        finally {
            this.isFetchingCurrentWorkspaceReview = false;
        }
    }
    *recreateWorkspaceAfterCommittingReview() {
        try {
            this.isRecreatingWorkspaceAfterCommittingReview = true;
            this.editorStore.applicationStore.alertService.setBlockingAlert({
                message: 'Recreating workspace...',
                prompt: 'Please do not close the application',
                showLoading: true,
            });
            yield this.editorStore.sdlcServerClient.createWorkspace(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, this.sdlcState.activeWorkspace.workspaceId, this.sdlcState.activeWorkspace.workspaceType);
            this.editorStore.applicationStore.navigationService.navigator.reload({
                ignoreBlocking: true,
            });
        }
        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.editorStore.applicationStore.alertService.setBlockingAlert(undefined);
            this.isRecreatingWorkspaceAfterCommittingReview = false;
        }
    }
    *closeWorkspaceReview() {
        if (!this.workspaceReview) {
            return;
        }
        this.isClosingWorkspaceReview = true;
        try {
            yield this.editorStore.sdlcServerClient.rejectReview(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, this.workspaceReview.id);
            this.workspaceReview = undefined;
        }
        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.isClosingWorkspaceReview = false;
        }
    }
    /**
     * Below functions will be specific to properties on the project such as reviews, tags, etc..
     */
    *createWorkspaceReview(title, reviewDescription) {
        // NOTE: We will only allow having dependencies on snapshots in workspace, not in project
        // Therefore, we block creation of review and committing review containing a change
        // in dependency on snapshot versions
        if (this.editorStore.projectConfigurationEditorState
            .containsSnapshotDependencies) {
            this.editorStore.applicationStore.notificationService.notifyWarning(`Can't create review: workspace contains snapshot dependencies`);
            return;
        }
        if (isProjectSandbox(this.sdlcState.activeProject)) {
            this.editorStore.applicationStore.notificationService.notifyWarning(`Can't create review: Reviews for sandbox projects not suppoorted`);
            return;
        }
        this.isCreatingWorkspaceReview = true;
        try {
            const description = reviewDescription ??
                `review from ${this.editorStore.applicationStore.config.appName} for workspace ${this.sdlcState.activeWorkspace.workspaceId}`;
            this.workspaceReview = Review.serialization.fromJson((yield this.editorStore.sdlcServerClient.createReview(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, {
                workspaceId: this.sdlcState.activeWorkspace.workspaceId,
                title,
                workspaceType: this.sdlcState.activeWorkspace.workspaceType,
                description,
            })));
        }
        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.isCreatingWorkspaceReview = false;
        }
    }
    *commitWorkspaceReview(review) {
        // NOTE: We will only allow having dependencies on snapshots in workspace, not in project
        // Therefore, we block creation of review and committing review containing a change
        // in dependency on snapshot versions
        if (this.editorStore.projectConfigurationEditorState
            .containsSnapshotDependencies) {
            this.editorStore.applicationStore.notificationService.notifyWarning(`Can't commit review: workspace contains snapshot dependencies`);
            return;
        }
        this.isCommittingWorkspaceReview = true;
        // check if the workspace is in conflict resolution mode
        try {
            const isInConflictResolutionMode = (yield flowResult(this.sdlcState.checkIfCurrentWorkspaceIsInConflictResolutionMode()));
            if (isInConflictResolutionMode) {
                this.editorStore.applicationStore.alertService.setBlockingAlert({
                    message: 'Workspace is in conflict resolution mode',
                    prompt: 'Please refresh the application',
                });
                return;
            }
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.notificationService.notifyWarning('Failed to check if current workspace is in conflict resolution mode');
            return;
        }
        try {
            yield this.editorStore.sdlcServerClient.commitReview(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, review.id, { message: `${review.title} [review]` });
            // Committing a review deletes the workspace on SDLC. Drop it from
            // the recents cache so the workspace setup screen doesn't keep
            // offering a dead link. Patch workspaces are never cached.
            if (this.sdlcState.activePatch === undefined) {
                LegendStudioUserDataHelper.workspaceSetup_removeRecentWorkspace(this.editorStore.applicationStore.userDataService, {
                    projectId: this.sdlcState.activeProject.projectId,
                    workspaceId: this.sdlcState.activeWorkspace.workspaceId,
                    workspaceType: this.sdlcState.activeWorkspace.workspaceType,
                });
            }
            this.editorStore.applicationStore.alertService.setActionAlertInfo({
                message: 'Committed review successfully',
                prompt: 'You can create a new workspace with the same name or leave for the start page',
                actions: [
                    {
                        label: 'Create new workspace',
                        handler: this.editorStore.applicationStore.guardUnhandledError(() => flowResult(this.recreateWorkspaceAfterCommittingReview())),
                        type: ActionAlertActionType.PROCEED,
                    },
                    {
                        label: 'Leave',
                        type: ActionAlertActionType.PROCEED,
                        handler: () => {
                            this.editorStore.applicationStore.navigationService.navigator.goToLocation(generateSetupRoute(this.editorStore.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id), {
                                ignoreBlocking: true,
                            });
                        },
                        default: true,
                    },
                ],
            });
        }
        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.isCommittingWorkspaceReview = false;
        }
    }
}
//# sourceMappingURL=WorkspaceReviewState.js.map