/**
 * 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 { EditorState } from '../EditorState.js';
import { action, computed, flow, observable, makeObservable, flowResult, } from 'mobx';
import { LogEvent, assertErrorThrown, guaranteeNonNullable, hashArray, ActionState, prettyCONSTName, } from '@finos/legend-shared';
import { ProjectStructureVersion, UpdateProjectConfigurationCommand, UpdatePlatformConfigurationsCommand, ProjectType, } from '@finos/legend-server-sdlc';
import { LEGEND_STUDIO_APP_EVENT } from '../../../../__lib__/LegendStudioEvent.js';
import { SNAPSHOT_ALIAS, StoreProjectData } from '@finos/legend-server-depot';
import { ProjectDependencyEditorState } from './ProjectDependencyEditorState.js';
export var CONFIGURATION_EDITOR_TAB;
(function (CONFIGURATION_EDITOR_TAB) {
    CONFIGURATION_EDITOR_TAB["PROJECT_STRUCTURE"] = "PROJECT_STRUCTURE";
    CONFIGURATION_EDITOR_TAB["PROJECT_DEPENDENCIES"] = "PROJECT_DEPENDENCIES";
    CONFIGURATION_EDITOR_TAB["PLATFORM_CONFIGURATIONS"] = "PLATFORM_CONFIGURATIONS";
    CONFIGURATION_EDITOR_TAB["ADVANCED"] = "ADVANCED";
})(CONFIGURATION_EDITOR_TAB || (CONFIGURATION_EDITOR_TAB = {}));
export const projectTypeTabFilter = (mode, tab) => {
    if (mode === ProjectType.EMBEDDED &&
        tab === CONFIGURATION_EDITOR_TAB.PLATFORM_CONFIGURATIONS) {
        return false;
    }
    return true;
};
export class ProjectConfigurationEditorState extends EditorState {
    sdlcState;
    updatingConfigurationState = ActionState.create();
    fetchingProjectVersionsState = ActionState.create();
    projectDependencyEditorState;
    originalProjectConfiguration; // TODO: we might want to remove this when we do change detection for project configuration
    projectConfiguration;
    selectedTab;
    isReadOnly = false;
    projects = new Map();
    versions = new Map();
    latestProjectStructureVersion;
    manualOverwrite = false;
    associatedProjectsAndVersionsFetched = false;
    constructor(editorStore, sdlcState) {
        super(editorStore);
        makeObservable(this, {
            originalProjectConfiguration: observable,
            updatingConfigurationState: observable,
            projectConfiguration: observable,
            selectedTab: observable,
            isReadOnly: observable,
            manualOverwrite: observable,
            projects: observable,
            versions: observable,
            associatedProjectsAndVersionsFetched: observable,
            fetchingProjectVersionsState: observable,
            latestProjectStructureVersion: observable,
            projectDependencyEditorState: observable,
            originalConfig: computed,
            isGroupIdChanged: computed,
            isArtifactIdChanged: computed,
            setOriginalProjectConfiguration: action,
            setProjectConfiguration: action,
            setSelectedTab: action,
            setManualOverwrite: action,
            fectchAssociatedProjectsAndVersions: flow,
            updateProjectConfiguration: flow,
            updateToLatestStructure: flow,
            updateConfigs: flow,
            fetchLatestProjectStructureVersion: flow,
            changeProjectType: flow,
        });
        this.projectDependencyEditorState = new ProjectDependencyEditorState(this, this.editorStore);
        this.selectedTab = CONFIGURATION_EDITOR_TAB.PROJECT_STRUCTURE;
        this.isReadOnly = editorStore.isInViewerMode;
        this.sdlcState = sdlcState;
    }
    setOriginalProjectConfiguration(projectConfiguration) {
        this.originalProjectConfiguration = projectConfiguration;
    }
    setProjectConfiguration(projectConfiguration) {
        this.projectConfiguration = projectConfiguration;
    }
    setSelectedTab(tab) {
        this.selectedTab = tab;
    }
    setManualOverwrite(value) {
        this.manualOverwrite = value;
    }
    get label() {
        return 'config';
    }
    match(tab) {
        return tab instanceof ProjectConfigurationEditorState;
    }
    get currentProjectConfiguration() {
        return guaranteeNonNullable(this.projectConfiguration, 'Project configuration must exist');
    }
    get originalConfig() {
        return guaranteeNonNullable(this.originalProjectConfiguration, 'Original project configuration is not set');
    }
    get isGroupIdChanged() {
        return (this.currentProjectConfiguration.groupId !==
            this.originalProjectConfiguration?.groupId);
    }
    get isArtifactIdChanged() {
        return (this.currentProjectConfiguration.artifactId !==
            this.originalProjectConfiguration?.artifactId);
    }
    get containsSnapshotDependencies() {
        return Boolean(this.originalProjectConfiguration?.projectDependencies.some((dependency) => dependency.versionId.endsWith(SNAPSHOT_ALIAS)));
    }
    get isInEmbeddedMode() {
        return (this.originalProjectConfiguration?.projectType === ProjectType.EMBEDDED);
    }
    *fectchAssociatedProjectsAndVersions() {
        this.fetchingProjectVersionsState.inProgress();
        try {
            (yield this.editorStore.depotServerClient.getProjects())
                .map((v) => StoreProjectData.serialization.fromJson(v))
                .forEach((project) => this.projects.set(project.coordinates, project));
            // fetch the versions for the dependency projects
            for (const dep of this.projectConfiguration?.projectDependencies ?? []) {
                const project = this.projects.get(dep.projectId);
                if (project) {
                    const _versions = (yield this.editorStore.depotServerClient.getVersions(guaranteeNonNullable(dep.groupId), guaranteeNonNullable(dep.artifactId), true));
                    this.versions.set(project.coordinates, _versions);
                }
            }
            this.associatedProjectsAndVersionsFetched = 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(`Can't get project dependencies data. Error:\n${error.message}`);
        }
        finally {
            this.fetchingProjectVersionsState.complete();
        }
    }
    *updateProjectConfiguration(updateConfigurationCommand) {
        try {
            this.updatingConfigurationState.inProgress();
            yield this.editorStore.sdlcServerClient.updateConfiguration(this.editorStore.sdlcState.activeProject.projectId, this.editorStore.sdlcState.activeWorkspace, UpdateProjectConfigurationCommand.serialization.toJson(updateConfigurationCommand));
            this.editorStore.reset();
            // reset editor
            yield flowResult(this.editorStore.sdlcState.fetchCurrentWorkspace(this.editorStore.sdlcState.activeProject.projectId, this.editorStore.sdlcState.activePatch?.patchReleaseVersionId.id, this.editorStore.sdlcState.activeWorkspace.workspaceId, this.editorStore.sdlcState.activeWorkspace.workspaceType));
            yield flowResult(this.sdlcState.fetchCurrentRevision(this.editorStore.sdlcState.activeProject.projectId, this.editorStore.sdlcState.activeWorkspace));
            yield flowResult(this.editorStore.initMode());
            this.editorStore.tabManagerState.openTab(this.editorStore.projectConfigurationEditorState);
        }
        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.updatingConfigurationState.complete();
        }
    }
    *updateToLatestStructure() {
        if (this.latestProjectStructureVersion) {
            try {
                let latestStructure = this.latestProjectStructureVersion;
                if (this.isInEmbeddedMode) {
                    const projectStructureVersion = new ProjectStructureVersion();
                    projectStructureVersion.version =
                        this.latestProjectStructureVersion.version;
                    // extension version does not exists in embedded mode
                    projectStructureVersion.extensionVersion = undefined;
                    latestStructure = projectStructureVersion;
                }
                const updateCommand = new UpdateProjectConfigurationCommand(this.currentProjectConfiguration.groupId, this.currentProjectConfiguration.artifactId, latestStructure, `update project configuration from ${this.editorStore.applicationStore.config.appName}: update to latest project structure`);
                yield flowResult(this.updateProjectConfiguration(updateCommand));
            }
            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);
            }
        }
    }
    *changeProjectType() {
        try {
            const newProjectType = this.isInEmbeddedMode
                ? ProjectType.MANAGED
                : ProjectType.EMBEDDED;
            const updateCommand = new UpdateProjectConfigurationCommand(this.currentProjectConfiguration.groupId, this.currentProjectConfiguration.artifactId, undefined, `update project configuration from ${this.editorStore.applicationStore.config.appName}: changed project type to ${prettyCONSTName(newProjectType)}`);
            updateCommand.projectType = newProjectType;
            yield flowResult(this.updateProjectConfiguration(updateCommand));
        }
        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);
        }
    }
    // TODO: we will probably need to remove this in the future when we have a better strategy for change detection and persistence of project config
    // See https://github.com/finos/legend-studio/issues/952
    *updateConfigs() {
        this.updatingConfigurationState.inProgress();
        this.editorStore.applicationStore.alertService.setBlockingAlert({
            message: `Updating project configuration...`,
            prompt: `Please do not reload the application`,
            showLoading: true,
        });
        try {
            const updateProjectConfigurationCommand = new UpdateProjectConfigurationCommand(this.currentProjectConfiguration.groupId, this.currentProjectConfiguration.artifactId, this.currentProjectConfiguration.projectStructureVersion, `update project configuration from ${this.editorStore.applicationStore.config.appName}`);
            if (hashArray(this.originalConfig.platformConfigurations ?? []) !==
                hashArray(this.currentProjectConfiguration.platformConfigurations ?? [])) {
                updateProjectConfigurationCommand.platformConfigurations =
                    new UpdatePlatformConfigurationsCommand(this.currentProjectConfiguration.platformConfigurations);
            }
            if (this.originalConfig.runDependencyTests !==
                this.currentProjectConfiguration.runDependencyTests) {
                updateProjectConfigurationCommand.runDependencyTests =
                    this.currentProjectConfiguration.runDependencyTests;
            }
            updateProjectConfigurationCommand.projectDependenciesToAdd =
                this.currentProjectConfiguration.projectDependencies.filter((dep) => !this.originalConfig.projectDependencies.find((originalProjDep) => originalProjDep.hashCode === dep.hashCode));
            updateProjectConfigurationCommand.projectDependenciesToRemove =
                this.originalConfig.projectDependencies.filter((originalProjDep) => !this.currentProjectConfiguration.projectDependencies.find((dep) => dep.hashCode === originalProjDep.hashCode));
            yield flowResult(this.updateProjectConfiguration(updateProjectConfigurationCommand));
        }
        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.updatingConfigurationState.complete();
            this.editorStore.applicationStore.alertService.setBlockingAlert(undefined);
        }
    }
    *fetchLatestProjectStructureVersion() {
        try {
            this.latestProjectStructureVersion =
                ProjectStructureVersion.serialization.fromJson((yield this.editorStore.sdlcServerClient.getLatestProjectStructureVersion()));
        }
        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);
        }
    }
}
//# sourceMappingURL=ProjectConfigurationEditorState.js.map