/**
 * 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 { DEFAULT_GENERATION_PACKAGE, EngineRuntime, Database, RelationalDatabaseConnection, PackageableElementExplicitReference, StoreConnections, IdentifiedConnection, GraphManagerState, getMappingCompatibleClasses, } from '@finos/legend-graph';
import { ActionState, assertErrorThrown, guaranteeNonNullable, assertTrue, } from '@finos/legend-shared';
import { action, flow, flowResult, makeObservable, observable } from 'mobx';
import { QueryBuilderAdvancedWorkflowState, QueryBuilderConfig, QueryBuilderState, } from '@finos/legend-query-builder';
import { DEFAULT_TAB_SIZE, } from '@finos/legend-application';
import { payloadDebugger } from '../../../panel-group/DevToolPanelState.js';
import { renderDatabaseQueryBuilderSetupPanelContent } from '../../../../../components/editor/editor-group/database/IsolatedQueryDatabase.js';
const replaceConnectionInEngineRuntime = (engineRuntime, connection, databse) => {
    const _storeConnection = new StoreConnections(PackageableElementExplicitReference.create(databse));
    const newconnection = new RelationalDatabaseConnection(PackageableElementExplicitReference.create(databse), connection.type, connection.datasourceSpecification, connection.authenticationStrategy);
    newconnection.localMode = connection.localMode;
    newconnection.timeZone = connection.timeZone;
    _storeConnection.storeConnections = [
        new IdentifiedConnection('connection1', newconnection),
    ];
    engineRuntime.connections = [_storeConnection];
};
export class IsolatedDatabaseBuilderState extends QueryBuilderState {
    database;
    globalGraphManagerState;
    engineRuntime;
    connectionKey;
    compatibleConnections;
    TEMPORARY__setupPanelContentRenderer = () => renderDatabaseQueryBuilderSetupPanelContent(this);
    constructor(applicationStore, isolatedGraphManagerState, globalGraphManagerState, database, connectionKey, runtime, compatibleConnections, acceptedElementPaths, config) {
        super(applicationStore, isolatedGraphManagerState, QueryBuilderAdvancedWorkflowState.INSTANCE, config);
        makeObservable(this, {
            connectionKey: observable,
            engineRuntime: observable,
            changeConnection: action,
        });
        this.database = database;
        this.globalGraphManagerState = globalGraphManagerState;
        this.engineRuntime = runtime;
        this.compatibleConnections = compatibleConnections;
        this.connectionKey = connectionKey;
        const classes = isolatedGraphManagerState.usableClasses;
        const electedMapping = guaranteeNonNullable(isolatedGraphManagerState.graph.mappings.filter((m) => acceptedElementPaths ? acceptedElementPaths.includes(m.path) : true)[0], 'Compatible mapping expected');
        this.class = guaranteeNonNullable(getMappingCompatibleClasses(electedMapping, classes)[0], 'Compatible class expected for mapping');
        this.executionContextState.mapping = electedMapping;
        this.executionContextState.runtimeValue = runtime;
    }
    changeConnection(key) {
        const connection = this.compatibleConnections.get(key);
        if (connection) {
            replaceConnectionInEngineRuntime(this.engineRuntime, connection, this.database);
            this.connectionKey = key;
        }
    }
}
export class QueryDatabaseState {
    editorStore;
    database;
    constructor(database, editorStore) {
        this.database = database;
        this.editorStore = editorStore;
        makeObservable(this, {
            init: flow,
        });
    }
    *init() {
        try {
            const compConnections = new Map();
            this.editorStore.graphManagerState.usableConnections.forEach((conn) => {
                const val = conn.connectionValue;
                if (val instanceof RelationalDatabaseConnection) {
                    compConnections.set(conn.path, val);
                }
            });
            assertTrue(compConnections.size > 0, `No compatible connections found for database ${this.database.path}`);
            const embeddedQueryBuilderState = this.editorStore.embeddedQueryBuilderState;
            const databaseGraphManagerState = new GraphManagerState(this.editorStore.applicationStore.pluginManager, this.editorStore.applicationStore.logService);
            yield databaseGraphManagerState.graphManager.initialize({
                env: this.editorStore.applicationStore.config.env,
                tabSize: DEFAULT_TAB_SIZE,
                clientConfig: {
                    baseUrl: this.editorStore.applicationStore.config.engineServerUrl,
                    queryBaseUrl: this.editorStore.applicationStore.config.engineQueryServerUrl,
                    enableCompression: true,
                    payloadDebugger,
                },
            }, {
                tracerService: this.editorStore.applicationStore.tracerService,
            });
            databaseGraphManagerState.graph =
                this.editorStore.graphManagerState.createNewGraph();
            const copiedDb = new Database(this.database.name);
            databaseGraphManagerState.graph.addElement(copiedDb, guaranteeNonNullable(this.database.package?.path));
            copiedDb.schemas = this.database.schemas;
            copiedDb.joins = this.database.joins;
            copiedDb.filters = this.database.filters;
            const entities = (yield this.editorStore.graphManagerState.graphManager.generateModelsFromDatabaseSpecification(this.database.path, DEFAULT_GENERATION_PACKAGE, this.editorStore.graphManagerState.graph));
            yield this.editorStore.graphManagerState.graphManager.buildGraph(databaseGraphManagerState.graph, entities, ActionState.create());
            const engineRuntime = new EngineRuntime();
            engineRuntime.mappings = databaseGraphManagerState.graph.mappings.map((e) => PackageableElementExplicitReference.create(e));
            const connectionEntry = guaranteeNonNullable(Array.from(compConnections.entries())[0]);
            const connection = connectionEntry[1];
            replaceConnectionInEngineRuntime(engineRuntime, connection, copiedDb);
            const config = new QueryBuilderConfig();
            const queryBuilderState = new IsolatedDatabaseBuilderState(this.editorStore.applicationStore, databaseGraphManagerState, this.editorStore.graphManagerState, copiedDb, connectionEntry[0], engineRuntime, compConnections, entities.map((e) => e.path), config);
            yield flowResult(embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration({
                setupQueryBuilderState: async () => queryBuilderState,
                actionConfigs: [],
            }));
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.notificationService.notifyError(`Unable to query database: ${error.message}`);
        }
    }
}
//# sourceMappingURL=QueryDatabaseState.js.map