/**
 * 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 { DataProduct, LakehouseAccessPoint, AccessPoint, stub_RawLambda, LakehouseTargetEnv, LAMBDA_PIPE, ParserError, GRAPH_MANAGER_EVENT, isStubbed_RawLambda, AccessPointGroup, CodeCompletionResult, getStereotype, ModelAccessPointGroup, Association, Class, Enumeration, Package, PackageableElementExplicitReference, Expertise, observe_DataProductElementScope, DataProductElementScope, RelationElementsData, RelationElement, observe_RelationElement, observe_RelationElementsData, V1_PureGraphManager, V1_LambdaReturnTypeInput, V1_transformRawLambda, V1_GraphTransformerContextBuilder, V1_relationTypeModelSchema, V1_RemoteEngine, DataElementReference, DataElement, DataProductDiagram, observe_DataProductDiagram, stub_Mapping, AppDirOwner, } from '@finos/legend-graph';
import { ElementEditorState } from '../ElementEditorState.js';
import { RelationElementState } from '../data/EmbeddedDataState.js';
import { action, computed, flow, flowResult, makeObservable, observable, runInAction, } from 'mobx';
import { guaranteeType, addUniqueEntry, assertErrorThrown, LogEvent, deleteEntry, filterByType, ActionState, guaranteeNonNullable, assertTrue, uuid, swapEntry, returnUndefOnError, } from '@finos/legend-shared';
import { accessPointGroup_swapAccessPoints, dataProduct_addAccessPoint, dataProduct_addAccessPointGroup, supportInfo_addExpertise, modelAccessPointGroup_addDiagram, dataProduct_deleteAccessPoint, dataProduct_deleteAccessPointGroup, modelAccessPointGroup_removeDiagram, dataProduct_swapAccessPointGroups, modelAccessPointGroup_addElement, modelAccessPointGroup_removeElement, modelAccessPointGroup_setElementExclude, modelAccessPointGroup_setMapping, dataProduct_setSupportInfoIfAbsent, } from '../../../../graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
import { DataProductTestableState } from './testable/DataProductTestableState.js';
import { LambdaEditorState, LineageState } from '@finos/legend-query-builder';
import { DataProductElementEditorInitialConfiguration, EditorInitialConfiguration, } from '../ElementEditorInitialConfiguration.js';
import { EXTERNAL_APPLICATION_NAVIGATION__generateUrlWithEditorConfig } from '../../../../../__lib__/LegendStudioNavigation.js';
import { deserialize } from 'serializr';
import { Diagram } from '@finos/legend-extension-dsl-diagram';
import { LegendStudioTelemetryHelper } from '../../../../../__lib__/LegendStudioTelemetryHelper.js';
import { onGeneratingDiagramFromMapping } from '../mapping/MappingEditorState.js';
export var DATA_PRODUCT_TAB;
(function (DATA_PRODUCT_TAB) {
    DATA_PRODUCT_TAB["HOME"] = "Home";
    DATA_PRODUCT_TAB["SUPPORT"] = "Support";
    DATA_PRODUCT_TAB["APG"] = "APG";
    DATA_PRODUCT_TAB["OPERATIONAL"] = "Operational";
    DATA_PRODUCT_TAB["TESTING"] = "Testing";
})(DATA_PRODUCT_TAB || (DATA_PRODUCT_TAB = {}));
export var DATA_PRODUCT_TYPE;
(function (DATA_PRODUCT_TYPE) {
    DATA_PRODUCT_TYPE["INTERNAL"] = "Internal";
    DATA_PRODUCT_TYPE["EXTERNAL"] = "External";
})(DATA_PRODUCT_TYPE || (DATA_PRODUCT_TYPE = {}));
export class AccessPointState {
    uuid = uuid();
    state;
    accessPoint;
    constructor(val, editorState) {
        this.accessPoint = val;
        this.state = editorState;
        makeObservable(this, {
            state: observable,
            accessPoint: observable,
            changeGroupState: action,
        });
    }
    get isRunningProcess() {
        return false;
    }
    changeGroupState(newGroup) {
        this.state = newGroup;
    }
}
export class AccessPointLambdaEditorState extends LambdaEditorState {
    editorStore;
    val;
    lambdaRelationColumns;
    isUpdatingRelationColumns = false;
    constructor(val) {
        super('', LAMBDA_PIPE, {
            typeAheadEnabled: true,
        });
        this.val = val;
        this.editorStore = val.state.state.editorStore;
        makeObservable(this, {
            lambdaRelationColumns: observable,
            isUpdatingRelationColumns: observable,
            setLambdaRelationColumns: action,
            updateLambdaRelationColumns: flow,
        });
        flowResult(this.updateLambdaRelationColumns()).catch(this.editorStore.applicationStore.alertUnhandledError);
    }
    setLambdaRelationColumns(columns) {
        this.lambdaRelationColumns = columns;
    }
    setIsUpdatingRelationColumns(value) {
        this.isUpdatingRelationColumns = value;
    }
    *updateLambdaRelationColumns() {
        // Prevent concurrent calls
        if (this.isUpdatingRelationColumns) {
            return;
        }
        this.setIsUpdatingRelationColumns(true);
        const relationElement = this.val.relationElementState?.relationElement;
        if (relationElement) {
            this.val.deleteRelationElement();
        }
        try {
            const model = guaranteeType(this.editorStore.graphManagerState.graphManager, V1_PureGraphManager).getFullGraphModelData(this.editorStore.graphManagerState.graph);
            const relationTypeInput = new V1_LambdaReturnTypeInput(model, V1_transformRawLambda(this.val.accessPoint.func, new V1_GraphTransformerContextBuilder(this.editorStore.pluginManager.getPureProtocolProcessorPlugins()).build()));
            const relationType = deserialize(V1_relationTypeModelSchema, (yield guaranteeType(guaranteeType(this.editorStore.graphManagerState.graphManager, V1_PureGraphManager).engine, V1_RemoteEngine)
                .getEngineServerClient()
                .lambdaRelationType(V1_LambdaReturnTypeInput.serialization.toJson(relationTypeInput))));
            this.setLambdaRelationColumns(relationType.columns.map((column) => column.name));
        }
        catch {
            this.setLambdaRelationColumns(undefined);
        }
        finally {
            if (relationElement) {
                this.val.addRelationElement(relationElement, false);
            }
            this.setIsUpdatingRelationColumns(false);
        }
    }
    get lambdaId() {
        return this.val.accessPoint.id;
    }
    get fullLambdaString() {
        return `${this.lambdaString}`;
    }
    *convertLambdaGrammarStringToObject() {
        const emptyLambda = stub_RawLambda();
        if (this.lambdaString) {
            try {
                const lambda = (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(this.fullLambdaString, this.lambdaId));
                this.setParserError(undefined);
                this.val.accessPoint.func = lambda;
            }
            catch (error) {
                assertErrorThrown(error);
                if (error instanceof ParserError) {
                    this.setParserError(error);
                }
                this.editorStore.applicationStore.logService.error(LogEvent.create(GRAPH_MANAGER_EVENT.PARSING_FAILURE), error);
            }
        }
        else {
            this.clearErrors();
            this.val.accessPoint.func = emptyLambda;
        }
    }
    *convertLambdaObjectToGrammarString(options) {
        if (!isStubbed_RawLambda(this.val.accessPoint.func) &&
            !this.val.state.state.isConvertingTransformLambdaObjects) {
            try {
                const lambdas = new Map();
                lambdas.set(this.lambdaId, this.val.accessPoint.func);
                const isolatedLambdas = (yield this.editorStore.graphManagerState.graphManager.lambdasToPureCode(lambdas, options?.pretty));
                const grammarText = isolatedLambdas.get(this.lambdaId);
                this.setLambdaString(grammarText !== undefined
                    ? this.extractLambdaString(grammarText)
                    : '');
                this.clearErrors({
                    preserveCompilationError: options?.preserveCompilationError,
                });
            }
            catch (error) {
                assertErrorThrown(error);
                this.editorStore.applicationStore.logService.error(LogEvent.create(GRAPH_MANAGER_EVENT.PARSING_FAILURE), error);
            }
        }
        else {
            this.clearErrors();
            this.setLambdaString('');
        }
    }
    async getCodeComplete(input) {
        try {
            return (await this.editorStore.graphManagerState.graphManager.getCodeComplete(input, this.editorStore.graphManagerState.graph, undefined, {
                ignoreElements: [this.val.state.state.product.path],
            }));
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(GRAPH_MANAGER_EVENT.PARSING_FAILURE), error);
            return new CodeCompletionResult();
        }
    }
}
export class LakehouseAccessPointState extends AccessPointState {
    lambdaState;
    artifactGenerationContent;
    generatingArtifactState = ActionState.create();
    relationElementState;
    showSampleValuesEditor = true;
    showSampleValuesModal = false;
    // Add lineage state and isGeneratingLineage
    lineageState;
    generatingLineageAction = ActionState.create();
    constructor(val, editorState) {
        super(val, editorState);
        makeObservable(this, {
            lambdaState: observable,
            artifactGenerationContent: observable,
            generatingArtifactState: observable,
            generateArtifact: flow,
            isRunningProcess: computed,
            relationElementState: observable,
            showSampleValuesEditor: observable,
            setShowSampleValuesEditor: action,
            showSampleValuesModal: observable,
            setShowSampleValuesModal: action,
            addRelationElement: action,
            deleteRelationElement: action,
            // Add observables for lineage
            lineageState: observable,
            setArtifactContent: action,
            generatingLineageAction: observable,
            generateLineage: flow,
            hasRelationElementMismatch: computed,
        });
        this.accessPoint = val;
        this.lambdaState = new AccessPointLambdaEditorState(this);
        this.lineageState = new LineageState(this.state.state.editorStore.applicationStore);
        this.relationElementState = this.getRelationElementState();
    }
    get hasRelationElementMismatch() {
        if (!this.relationElementState) {
            return false;
        }
        const relationElement = this.relationElementState.relationElement;
        const lambdaColumns = this.lambdaState.lambdaRelationColumns;
        if (lambdaColumns === undefined) {
            return true;
        }
        const relationColumnSet = new Set(relationElement.columns);
        const lambdaColumnSet = new Set(lambdaColumns);
        if (relationColumnSet.size !== lambdaColumnSet.size) {
            return true;
        }
        return !Array.from(lambdaColumnSet).every((col) => relationColumnSet.has(col));
    }
    getRelationElementMismatchMessage() {
        if (!this.hasRelationElementMismatch) {
            return undefined;
        }
        const lambdaColumns = this.lambdaState.lambdaRelationColumns;
        if (lambdaColumns === undefined) {
            return `Fix compiler errors and make sure AccessPoint ${this.accessPoint.id} returns a Relation type`;
        }
        return `Sample values columns must match: [${lambdaColumns.join(', ')}]`;
    }
    setShowSampleValuesEditor(value) {
        this.showSampleValuesEditor = value;
    }
    setShowSampleValuesModal(value) {
        this.showSampleValuesModal = value;
    }
    getRelationElementState() {
        const relationElement = this.getRelationElement();
        return relationElement
            ? new RelationElementState(relationElement)
            : undefined;
    }
    getRelationElement() {
        const product = this.state.state.product;
        if (!product.sampleValues) {
            return undefined;
        }
        for (const embeddedData of product.sampleValues) {
            if (embeddedData instanceof RelationElementsData) {
                const relationElement = embeddedData.relationElements.find((res) => res.paths[0] === this.accessPoint.id);
                if (relationElement) {
                    return relationElement;
                }
            }
        }
        return undefined;
    }
    relationElementExistsinDataElementReference() {
        const product = this.state.state.product;
        if (!product.sampleValues) {
            return undefined;
        }
        for (const embeddedData of product.sampleValues) {
            if (embeddedData instanceof DataElementReference) {
                const dataElement = embeddedData.dataElement.value;
                if (dataElement instanceof DataElement &&
                    dataElement.data instanceof RelationElementsData) {
                    const relationElement = dataElement.data.relationElements.find((res) => res.paths[0] === this.accessPoint.id);
                    if (relationElement) {
                        return dataElement.path;
                    }
                }
            }
        }
        return undefined;
    }
    createAndaddRelationElement() {
        const newElement = new RelationElement();
        newElement.paths = [this.accessPoint.id];
        if (this.lambdaState.lambdaRelationColumns) {
            newElement.columns = [...this.lambdaState.lambdaRelationColumns];
        }
        else {
            this.state.state.editorStore.applicationStore.notificationService.notifyError(`Can't get AccessPoint Relation columns. Fix compiler errors and make sure AccessPoint ${this.accessPoint.id} returns a Relation`);
            return;
        }
        newElement.rows = [];
        this.addRelationElement(observe_RelationElement(newElement), true);
    }
    addRelationElement(newElement, openModal) {
        const product = this.state.state.product;
        let relationElementsData = product.sampleValues?.find((embeddedData) => embeddedData instanceof RelationElementsData);
        if (!relationElementsData) {
            if (!product.sampleValues) {
                product.sampleValues = [];
            }
            relationElementsData = observe_RelationElementsData(new RelationElementsData());
            relationElementsData.relationElements = [];
            product.sampleValues.push(relationElementsData);
        }
        addUniqueEntry(relationElementsData.relationElements, newElement);
        this.relationElementState = new RelationElementState(newElement);
        if (openModal) {
            this.setShowSampleValuesModal(true);
        }
    }
    deleteRelationElement() {
        const product = this.state.state.product;
        if (!product.sampleValues) {
            return;
        }
        product.sampleValues.forEach((embeddedData) => {
            if (embeddedData instanceof RelationElementsData) {
                const elementToRemove = embeddedData.relationElements.find((re) => re.paths[0] === this.accessPoint.id);
                if (elementToRemove) {
                    deleteEntry(embeddedData.relationElements, elementToRemove);
                }
            }
        });
        product.sampleValues = product.sampleValues.filter((ed) => !(ed instanceof RelationElementsData) || ed.relationElements.length > 0);
        if (product.sampleValues.length === 0) {
            product.sampleValues = undefined;
        }
        if (this.relationElementState) {
            this.relationElementState = undefined;
        }
    }
    get editorStore() {
        return this.state.state.editorStore;
    }
    get isRunningProcess() {
        return (this.generatingArtifactState.isInProgress ||
            this.generatingLineageAction.isInProgress);
    }
    setArtifactContent(val) {
        this.artifactGenerationContent = val;
    }
    *generateLineage() {
        if (this.generatingLineageAction.isInProgress) {
            return;
        }
        try {
            this.generatingLineageAction.inProgress();
            const lambda = this.accessPoint.func;
            const lineageRawData = (yield this.editorStore.graphManagerState.graphManager.generateLineage(lambda, undefined, undefined, this.editorStore.graphManagerState.graph, undefined));
            const lineageData = this.editorStore.graphManagerState.graphManager.buildLineage(lineageRawData);
            this.lineageState.setLineageData(lineageData);
            this.generatingLineageAction.complete();
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.logService.error(LogEvent.create(GRAPH_MANAGER_EVENT.LINEAGE_GENERATION_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
        finally {
            this.generatingLineageAction.complete();
        }
    }
    *generateArtifact() {
        try {
            this.generatingArtifactState.inProgress();
            const generatedArtifacts = (yield this.editorStore.graphManagerState.graphManager.generateArtifacts(this.editorStore.graphManagerState.graph, this.editorStore.graphEditorMode.getGraphTextInputOption(), [this.state.state.elementPath]));
            const dataProductExtension = 'dataProduct';
            const dataProductArtifact = generatedArtifacts.values.filter((artifact) => artifact.extension === dataProductExtension);
            const dataProductContent = dataProductArtifact[0]?.artifactsByExtensionElements[0]?.files[0]
                ?.content ?? null;
            if (dataProductContent) {
                const contentJson = JSON.parse(dataProductContent);
                const apPlanGeneration = contentJson.accessPointGroups
                    .find((group) => group.id === this.state.value.id)
                    ?.accessPointImplementations.find((apImplementation) => apImplementation.id === this.accessPoint.id);
                this.artifactGenerationContent = JSON.stringify(apPlanGeneration, null, 2);
            }
            else {
                throw new Error('Could not find contents of this data product artifact');
            }
        }
        catch (error) {
            this.editorStore.applicationStore.notificationService.notifyError(`Failed to fetch access point plan generation: ${error}`);
        }
        finally {
            this.generatingArtifactState.complete();
        }
    }
}
export class AccessPointGroupState {
    state;
    uuid = uuid();
    value;
    accessPointStates = [];
    constructor(val, editorState) {
        this.value = val;
        this.state = editorState;
        this.accessPointStates = val.accessPoints.map((e) => this.buildAccessPointState(e));
        makeObservable(this, {
            value: observable,
            accessPointStates: observable,
            addAccessPoint: action,
            deleteAccessPoint: action,
            swapAccessPoints: action,
            containsPublicStereotype: computed,
        });
    }
    get isRunningProcess() {
        return Boolean(this.accessPointStates.find((e) => e.isRunningProcess));
    }
    get containsPublicStereotype() {
        return this.value.stereotypes.find((stereotype) => stereotype.value === this.publicStereotype);
    }
    get publicStereotype() {
        const publicStereotype = this.state.editorStore.applicationStore.config.options.dataProductConfig
            ?.publicStereotype;
        if (publicStereotype) {
            return returnUndefOnError(() => getStereotype(this.state.editorStore.graphManagerState.graph.getProfile(publicStereotype.profile), publicStereotype.stereotype));
        }
        return undefined;
    }
    hasErrors() {
        return (this.accessPointStates.length === 0 ||
            this.value.id === '' ||
            !this.value.description ||
            !this.value.title ||
            Boolean(this.accessPointStates.find((apState) => apState.accessPoint.id === '')) ||
            Boolean(this.accessPointStates.find((apState) => !apState.accessPoint.title)) ||
            Boolean(this.accessPointStates.find((apState) => !apState.accessPoint.description)));
    }
    deleteAccessPoint(val) {
        const state = this.accessPointStates.find((a) => a === val);
        if (state instanceof LakehouseAccessPointState) {
            state.deleteRelationElement();
        }
        deleteEntry(this.accessPointStates, state);
        dataProduct_deleteAccessPoint(this.value, val.accessPoint);
    }
    addAccessPoint(point) {
        const accessPointState = point instanceof AccessPoint ? this.buildAccessPointState(point) : point;
        addUniqueEntry(this.accessPointStates, accessPointState);
        dataProduct_addAccessPoint(this.value, accessPointState.accessPoint);
    }
    swapAccessPoints(sourceAccessPoint, targetAccessPoint) {
        swapEntry(this.accessPointStates, sourceAccessPoint, targetAccessPoint);
        accessPointGroup_swapAccessPoints(this.value, sourceAccessPoint.accessPoint, targetAccessPoint.accessPoint);
    }
    buildAccessPointState(val) {
        if (val instanceof LakehouseAccessPoint) {
            return new LakehouseAccessPointState(val, this);
        }
        return new AccessPointState(val, this);
    }
}
export class ModelAccessPointGroupState extends AccessPointGroupState {
    editorState;
    showNewModal = false;
    constructor(val, editorState) {
        super(val, editorState);
        this.value = val;
        this.editorState = editorState;
        makeObservable(this, {
            generateDiagramFromMapping: flow,
        });
    }
    hasErrors() {
        return (this.value.id === '' ||
            !this.value.description ||
            !this.value.title ||
            this.value.mapping.value.path === '' ||
            this.value.diagrams.length === 0);
    }
    setMapping(mapping) {
        modelAccessPointGroup_setMapping(this.value, PackageableElementExplicitReference.create(mapping));
    }
    getCompatibleDiagramOptions() {
        const currentDiagrams = this.value.diagrams.map((diagram) => diagram.diagram);
        return this.state.editorStore.graphManagerState.graph.allOwnElements
            .filter((element) => element instanceof Diagram)
            .filter((diagram) => !currentDiagrams.includes(diagram))
            .map((diagram) => ({
            label: diagram.path,
            value: diagram,
        }));
    }
    collectFeaturedClasses = (element, excludedPaths, elements) => {
        if (excludedPaths.includes(element.path)) {
            return;
        }
        if (element instanceof Class) {
            elements.add(element);
        }
        else if (element instanceof Package) {
            this.collectClassesFromPackage(element, excludedPaths, elements);
        }
    };
    collectClassesFromPackage = (element, excludedPaths, elements) => {
        element.children.forEach((child) => {
            if (excludedPaths.includes(child.path)) {
                return;
            }
            if (child instanceof Class) {
                elements.add(child);
            }
            else if (child instanceof Package) {
                this.collectClassesFromPackage(child, excludedPaths, elements);
            }
        });
    };
    addDiagram = (option) => {
        const diagramValue = option.value;
        const newDiagram = observe_DataProductDiagram(new DataProductDiagram());
        newDiagram.title = diagramValue.name;
        newDiagram.diagram = diagramValue;
        modelAccessPointGroup_addDiagram(this.value, newDiagram);
    };
    handleRemoveDiagram = (diagram) => {
        modelAccessPointGroup_removeDiagram(this.value, diagram);
    };
    *generateDiagramFromMapping() {
        const mapping = this.value.mapping.value;
        if (mapping.path === '') {
            return;
        }
        let featuredClasses = undefined;
        if (this.value.featuredElements.length > 0) {
            const includes = this.value.featuredElements
                .filter((el) => el.exclude === undefined || el.exclude === false)
                .map((el) => el.element.value);
            const excludedPaths = this.value.featuredElements
                .filter((el) => el.exclude !== undefined && el.exclude === true)
                .map((el) => el.element.value.path);
            const elements = new Set();
            includes.forEach((element) => {
                this.collectFeaturedClasses(element, excludedPaths, elements);
            });
            featuredClasses = Array.from(elements);
        }
        const diagram = (yield flowResult(onGeneratingDiagramFromMapping(mapping, this.state.editorStore, featuredClasses)));
        if (diagram) {
            const newDiagram = observe_DataProductDiagram(new DataProductDiagram());
            newDiagram.title = diagram.name;
            newDiagram.diagram = diagram;
            modelAccessPointGroup_addDiagram(this.value, newDiagram);
        }
    }
    addFeaturedElement(element) {
        const elementPointer = observe_DataProductElementScope(new DataProductElementScope());
        elementPointer.element =
            PackageableElementExplicitReference.create(element);
        modelAccessPointGroup_addElement(this.value, elementPointer);
    }
    removeFeaturedElement(element) {
        modelAccessPointGroup_removeElement(this.value, element);
    }
    excludeFeaturedElement(element, value) {
        modelAccessPointGroup_setElementExclude(element, value);
    }
    isValidDataProductElement(element) {
        return (element instanceof Package ||
            element instanceof Class ||
            element instanceof Enumeration ||
            element instanceof Association);
    }
    getFeaturedElementOptions() {
        const currentElements = this.value.featuredElements.map((elementPointer) => elementPointer.element.value);
        return this.state.editorStore.graphManagerState.graph.allOwnElements
            .filter((element) => this.isValidDataProductElement(element))
            .filter((element) => !currentElements.includes(element))
            .map((element) => ({
            label: element.path,
            value: element,
        }));
    }
}
const createEditorInitialConfiguration = () => {
    const config = new EditorInitialConfiguration();
    const ingest = new DataProductElementEditorInitialConfiguration();
    ingest.deployOnOpen = true;
    config.elementEditorConfiguration = ingest;
    return config;
};
const editorInitialConfigToBase64 = (val) => btoa(JSON.stringify(EditorInitialConfiguration.serialization.toJson(val)));
export const generateUrlToDeployOnOpen = (val) => {
    return val.editorStore.applicationStore.navigationService.navigator.generateAddress(EXTERNAL_APPLICATION_NAVIGATION__generateUrlWithEditorConfig(val.editorStore.editorMode.generateElementLink(val.product.path), editorInitialConfigToBase64(createEditorInitialConfiguration())));
};
export class DataProductEditorState extends ElementEditorState {
    deploymentState = ActionState.create();
    accessPointGroupStates = [];
    isConvertingTransformLambdaObjects = false;
    deployOnOpen = false;
    deployResponse;
    selectedGroupState;
    selectedTab;
    modelledDataProduct = false;
    testableState;
    constructor(editorStore, element, config) {
        super(editorStore, element);
        makeObservable(this, {
            product: computed,
            accessPointGroupStates: observable,
            isConvertingTransformLambdaObjects: observable,
            selectedTab: observable,
            modelledDataProduct: observable,
            setSelectedTab: action,
            addGroupState: action,
            deleteGroupState: action,
            deploy: flow,
            deployOnOpen: observable,
            deployResponse: observable,
            setDeployOnOpen: action,
            setDeployResponse: action,
            addAccessPoint: action,
            convertAccessPointsFuncObjects: flow,
            selectedGroupState: observable,
            setSelectedGroupState: action,
            swapAccessPointGroups: action,
        });
        this.accessPointGroupStates = this.product.accessPointGroups.map((e) => {
            if (e instanceof ModelAccessPointGroup) {
                this.modelledDataProduct = true;
                return new ModelAccessPointGroupState(e, this);
            }
            else if (e instanceof AccessPointGroup) {
                return new AccessPointGroupState(e, this);
            }
            else {
                throw new Error(`Can't build access point group state for unsupported access point group type: ${e}`);
            }
        });
        this.selectedGroupState = this.accessPointGroupStates[0];
        const elementConfig = config?.elementEditorConfiguration;
        if (elementConfig instanceof DataProductElementEditorInitialConfiguration) {
            this.deployOnOpen = elementConfig.deployOnOpen ?? false;
        }
        this.selectedTab = DATA_PRODUCT_TAB.HOME;
        this.testableState = new DataProductTestableState(this);
    }
    setDeployOnOpen(value) {
        this.deployOnOpen = value;
    }
    setDeployResponse(response) {
        this.deployResponse = response;
    }
    setSelectedTab(value) {
        this.selectedTab = value;
    }
    addGroupState(value) {
        this.accessPointGroupStates.push(value);
    }
    deleteGroupState(value) {
        deleteEntry(this.accessPointGroupStates, this.accessPointGroupStates.find((a) => a === value));
    }
    swapAccessPointGroups(sourceGroup, targetGroup) {
        swapEntry(this.accessPointGroupStates, sourceGroup, targetGroup);
        dataProduct_swapAccessPointGroups(this.product, sourceGroup.value, targetGroup.value);
    }
    *convertAccessPointsFuncObjects() {
        const lambdas = new Map();
        const index = new Map();
        const states = this.accessPointGroupStates
            .map((e) => e.accessPointStates)
            .flat()
            .filter(filterByType(LakehouseAccessPointState));
        states.forEach((pm) => {
            if (!isStubbed_RawLambda(pm.accessPoint.func)) {
                lambdas.set(pm.lambdaState.lambdaId, pm.accessPoint.func);
                index.set(pm.lambdaState.lambdaId, pm);
            }
        });
        if (lambdas.size) {
            this.isConvertingTransformLambdaObjects = true;
            try {
                const isolatedLambdas = (yield this.editorStore.graphManagerState.graphManager.lambdasToPureCode(lambdas));
                isolatedLambdas.forEach((grammarText, key) => {
                    const purePropertyMapping = index.get(key);
                    if (purePropertyMapping?.lambdaState.lambdaPrefix &&
                        grammarText.startsWith(purePropertyMapping.lambdaState.lambdaPrefix)) {
                        purePropertyMapping.lambdaState.setLambdaString(purePropertyMapping.lambdaState.extractLambdaString(grammarText));
                    }
                    else {
                        purePropertyMapping?.lambdaState.setLambdaString(grammarText);
                    }
                });
            }
            catch (error) {
                assertErrorThrown(error);
                this.editorStore.applicationStore.logService.error(LogEvent.create(GRAPH_MANAGER_EVENT.PARSING_FAILURE), error);
            }
            finally {
                this.isConvertingTransformLambdaObjects = false;
            }
        }
    }
    setSelectedGroupState(val) {
        this.selectedGroupState = val;
    }
    addAccessPoint(id, description, accessPointGroup) {
        const groupState = accessPointGroup instanceof AccessPointGroupState
            ? accessPointGroup
            : this.createGroupAndAdd(accessPointGroup);
        const accesspoint = new LakehouseAccessPoint(id, LakehouseTargetEnv.Snowflake, stub_RawLambda(), groupState.value);
        accesspoint.description = description;
        groupState.addAccessPoint(accesspoint);
        addUniqueEntry(this.accessPointGroupStates, groupState);
    }
    createGroupAndAdd(id, description, modeled) {
        const existingGroupState = this.accessPointGroupStates.find((groupState) => groupState.value.id === id);
        if (existingGroupState) {
            return existingGroupState;
        }
        let newGroupState;
        if (modeled) {
            const group = new ModelAccessPointGroup();
            group.id = id;
            group.mapping =
                PackageableElementExplicitReference.create(stub_Mapping());
            dataProduct_addAccessPointGroup(this.product, group);
            newGroupState = new ModelAccessPointGroupState(group, this);
            this.addGroupState(newGroupState);
        }
        else {
            const group = new AccessPointGroup();
            group.id = id;
            group.description = description;
            dataProduct_addAccessPointGroup(this.product, group);
            newGroupState = new AccessPointGroupState(group, this);
            this.addGroupState(newGroupState);
        }
        return newGroupState;
    }
    deleteAccessPointGroup(val) {
        const state = this.accessPointGroupStates.find((a) => a === val);
        runInAction(() => {
            if (state) {
                this.deleteGroupState(state);
                if (state === this.selectedGroupState) {
                    this.setSelectedGroupState(this.accessPointGroupStates[0]);
                }
            }
            dataProduct_deleteAccessPointGroup(this.product, val.value);
        });
    }
    createExpertise() {
        dataProduct_setSupportInfoIfAbsent(this.product);
        const newExpertise = new Expertise();
        if (this.product.supportInfo) {
            supportInfo_addExpertise(this.product.supportInfo, newExpertise);
        }
    }
    *deploy(token) {
        try {
            assertTrue(this.validForDeployment, 'Data product definition is not valid for deployment');
            this.deploymentState.inProgress();
            // The grammar we provide will be for the current data product + all ingests (used for compilation)
            const grammar = (yield this.editorStore.graphManagerState.graphManager.elementsToPureCode([...this.editorStore.graphManagerState.graph.ingests, this.product]));
            const response = (yield guaranteeNonNullable(this.ingestionManager).deployDataProduct(grammar, guaranteeNonNullable(this.appDirDeployment), (val) => this.editorStore.applicationStore.alertService.setBlockingAlert({
                message: val,
                showLoading: true,
            }), token));
            LegendStudioTelemetryHelper.logEvent_LakehouseDeployDataProduct(this.editorStore.applicationStore.telemetryService, this.editorStore.editorMode.getSourceInfo(), this.product.path);
            this.setDeployResponse(response);
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.notificationService.notifyError(`Ingest definition failed to deploy: ${error.message}`);
            LegendStudioTelemetryHelper.logEvent_LakehouseDeployDataProductFailure(this.editorStore.applicationStore.telemetryService, this.editorStore.editorMode.getSourceInfo(), this.product.path, error.message);
        }
        finally {
            this.deploymentState.complete();
            this.editorStore.applicationStore.alertService.setBlockingAlert(undefined);
        }
    }
    clearSupportInfo() {
        const supportInfo = this.product.supportInfo;
        runInAction(() => {
            //if the url is empty, the label should be too
            if (supportInfo?.documentation && !supportInfo.documentation.url) {
                supportInfo.documentation = undefined;
            }
            else if (supportInfo?.website && !supportInfo.website.url) {
                supportInfo.website = undefined;
            }
            else if (supportInfo?.faqUrl && !supportInfo.faqUrl.url) {
                supportInfo.faqUrl = undefined;
            }
            else if (supportInfo?.supportUrl && !supportInfo.supportUrl.url) {
                supportInfo.supportUrl = undefined;
            }
            //clear support info section if everything is clear
            if (!supportInfo?.documentation &&
                !supportInfo?.website &&
                !supportInfo?.faqUrl &&
                !supportInfo?.supportUrl &&
                supportInfo?.emails.length === 0) {
                this.product.supportInfo = undefined;
            }
        });
    }
    get product() {
        return guaranteeType(this.element, DataProduct, 'Element inside data product editor state must be a data product');
    }
    get validForDeployment() {
        return Boolean(this.appDirDeployment && this.ingestionManager);
    }
    get accessPoints() {
        return this.product.accessPointGroups.map((e) => e.accessPoints).flat();
    }
    get ingestionManager() {
        return this.editorStore.ingestionManager;
    }
    get deployValidationMessage() {
        if (!this.appDirDeployment) {
            return 'No app dir deployment found';
        }
        else if (!this.ingestionManager) {
            return 'No ingestion manager found';
        }
        return 'Deploy';
    }
    // Use explicit owner from the data product if available, otherwise fall back to the associated ingest's app dir deployment
    get appDirDeployment() {
        const owner = this.product.owner;
        if (owner instanceof AppDirOwner) {
            return owner.production;
        }
        return this.associatedIngest?.appDirDeployment;
    }
    // We need to get the associated Ingest to get the app dir deployment
    // We could do a more in depth check on the access point lambdas to check which ingest it uses but for now
    // we will assume all ingests have the same DID
    // we get the last one, to prioritize the ones in the current project followed by dependency ones
    get associatedIngest() {
        return this.editorStore.graphManagerState.graph.ingests.slice(-1)[0];
    }
    reprocess(newElement, editorStore) {
        const editorState = new DataProductEditorState(editorStore, newElement);
        return editorState;
    }
}
//# sourceMappingURL=DataProductEditorState.js.map