/**
 * 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 { computed, observable, action, makeObservable } from 'mobx';
import { guaranteeType, uuid, UnsupportedOperationError, } from '@finos/legend-shared';
import { ElementEditorState } from './../ElementEditorState.js';
import { PackageableConnection, JsonModelConnection, FlatDataConnection, RelationalDatabaseConnection, DefaultH2AuthenticationStrategy, DelegatedKerberosAuthenticationStrategy, OAuthAuthenticationStrategy, UsernamePasswordAuthenticationStrategy, ApiTokenAuthenticationStrategy, SnowflakePublicAuthenticationStrategy, GCPApplicationDefaultCredentialsAuthenticationStrategy, GCPWorkloadIdentityFederationAuthenticationStrategy, MiddleTierUsernamePasswordAuthenticationStrategy, TrinoDelegatedKerberosAuthenticationStrategy, EmbeddedH2DatasourceSpecification, LocalH2DatasourceSpecification, DatabricksDatasourceSpecification, SnowflakeDatasourceSpecification, BigQueryDatasourceSpecification, StaticDatasourceSpecification, RedshiftDatasourceSpecification, SpannerDatasourceSpecification, TrinoDatasourceSpecification, TrinoSslSpecification, createValidationError, isStubbed_PackageableElement, MapperPostProcessor, } from '@finos/legend-graph';
import { relationDbConnection_setNewAuthenticationStrategy, relationDbConnection_setDatasourceSpecification, relationDbConnection_setLocalMode, } from '../../../../graph-modifier/STO_Relational_GraphModifierHelper.js';
import { MapperPostProcessorEditorState, } from './PostProcessorEditorState.js';
export class ConnectionValueState {
    editorStore;
    connection;
    constructor(editorStore, connection) {
        this.editorStore = editorStore;
        this.connection = connection;
    }
}
export var RELATIONAL_DATABASE_TAB_TYPE;
(function (RELATIONAL_DATABASE_TAB_TYPE) {
    RELATIONAL_DATABASE_TAB_TYPE["GENERAL"] = "General";
    RELATIONAL_DATABASE_TAB_TYPE["STORE"] = "Store";
    RELATIONAL_DATABASE_TAB_TYPE["POST_PROCESSORS"] = "Post Processors";
})(RELATIONAL_DATABASE_TAB_TYPE || (RELATIONAL_DATABASE_TAB_TYPE = {}));
// Please do not change these values unless they change in the backend
export var CORE_DATASOURCE_SPEC_TYPE;
(function (CORE_DATASOURCE_SPEC_TYPE) {
    CORE_DATASOURCE_SPEC_TYPE["STATIC"] = "static";
    CORE_DATASOURCE_SPEC_TYPE["H2_LOCAL"] = "h2Local";
    CORE_DATASOURCE_SPEC_TYPE["H2_EMBEDDED"] = "h2Embedded";
    CORE_DATASOURCE_SPEC_TYPE["DATABRICKS"] = "databricks";
    CORE_DATASOURCE_SPEC_TYPE["SNOWFLAKE"] = "snowflake";
    CORE_DATASOURCE_SPEC_TYPE["REDSHIFT"] = "redshift";
    CORE_DATASOURCE_SPEC_TYPE["BIGQUERY"] = "bigQuery";
    CORE_DATASOURCE_SPEC_TYPE["SPANNER"] = "spanner";
    CORE_DATASOURCE_SPEC_TYPE["TRINO"] = "Trino";
})(CORE_DATASOURCE_SPEC_TYPE || (CORE_DATASOURCE_SPEC_TYPE = {}));
export var POST_PROCESSOR_TYPE;
(function (POST_PROCESSOR_TYPE) {
    POST_PROCESSOR_TYPE["MAPPER"] = "Mapper";
})(POST_PROCESSOR_TYPE || (POST_PROCESSOR_TYPE = {}));
// Please do not change these values unless they change in the backend
export var CORE_AUTHENTICATION_STRATEGY_TYPE;
(function (CORE_AUTHENTICATION_STRATEGY_TYPE) {
    CORE_AUTHENTICATION_STRATEGY_TYPE["DELEGATED_KERBEROS"] = "delegatedKerberos";
    CORE_AUTHENTICATION_STRATEGY_TYPE["H2_DEFAULT"] = "h2Default";
    CORE_AUTHENTICATION_STRATEGY_TYPE["SNOWFLAKE_PUBLIC"] = "snowflakePublic";
    CORE_AUTHENTICATION_STRATEGY_TYPE["GCP_APPLICATION_DEFAULT_CREDENTIALS"] = "gcpApplicationDefaultCredentials";
    CORE_AUTHENTICATION_STRATEGY_TYPE["API_TOKEN"] = "apiToken";
    CORE_AUTHENTICATION_STRATEGY_TYPE["OAUTH"] = "oauth";
    CORE_AUTHENTICATION_STRATEGY_TYPE["USERNAME_PASSWORD"] = "userNamePassword";
    CORE_AUTHENTICATION_STRATEGY_TYPE["GCP_WORKLOAD_IDENTITY_FEDERATION"] = "gcpWorkloadIdentityFederation";
    CORE_AUTHENTICATION_STRATEGY_TYPE["MIDDLE_TIER_USERNAME_PASSWORD"] = "middleTierUserNamePassword";
    CORE_AUTHENTICATION_STRATEGY_TYPE["TRINO_DELEGATED_KERBEROS"] = "TrinoDelegatedKerberosAuth";
})(CORE_AUTHENTICATION_STRATEGY_TYPE || (CORE_AUTHENTICATION_STRATEGY_TYPE = {}));
export class RelationalDatabaseConnectionValueState extends ConnectionValueState {
    connection;
    localMode = false;
    selectedTab = RELATIONAL_DATABASE_TAB_TYPE.GENERAL;
    postProcessorState;
    constructor(editorStore, connection) {
        super(editorStore, connection);
        makeObservable(this, {
            localMode: observable,
            selectedTab: observable,
            postProcessorState: observable,
            selectedValidDatasources: computed,
            connection: observable,
            setLocalMode: action,
            setSelectedTab: action,
            selectPostProcessor: action,
        });
        this.connection = connection;
    }
    selectPostProcessor = (postProcessor) => {
        if (postProcessor) {
            if (postProcessor instanceof MapperPostProcessor) {
                this.postProcessorState = new MapperPostProcessorEditorState(postProcessor, this);
            }
            else {
                const extraPostProcessorStateCreators = this.editorStore.pluginManager
                    .getApplicationPlugins()
                    .flatMap((plugin) => plugin.getExtraPostProcessorStateCreators?.() ?? []);
                for (const creator of extraPostProcessorStateCreators) {
                    const postProcessorState = creator(postProcessor, this);
                    if (postProcessorState) {
                        this.postProcessorState = postProcessorState;
                    }
                }
            }
        }
        if (this.postProcessorState) {
            this.postProcessorState.setPostProcessorState(postProcessor);
        }
    };
    get storeValidationResult() {
        return !this.connection.store ||
            isStubbed_PackageableElement(this.connection.store.value)
            ? createValidationError(['Connection database is empty'])
            : undefined;
    }
    setSelectedTab(val) {
        this.selectedTab = val;
    }
    setLocalMode(val) {
        this.localMode = val;
    }
    label() {
        return `${this.connection.type} connection`;
    }
    selectedDatasourceSpecificationType(spec) {
        if (spec instanceof StaticDatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.STATIC;
        }
        else if (spec instanceof EmbeddedH2DatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.H2_EMBEDDED;
        }
        else if (spec instanceof DatabricksDatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.DATABRICKS;
        }
        else if (spec instanceof SnowflakeDatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.SNOWFLAKE;
        }
        else if (spec instanceof BigQueryDatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.BIGQUERY;
        }
        else if (spec instanceof LocalH2DatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.H2_LOCAL;
        }
        else if (spec instanceof RedshiftDatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.REDSHIFT;
        }
        else if (spec instanceof SpannerDatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.SPANNER;
        }
        else if (spec instanceof TrinoDatasourceSpecification) {
            return CORE_DATASOURCE_SPEC_TYPE.TRINO;
        }
        const extraDatasourceSpecificationClassifiers = this.editorStore.pluginManager
            .getApplicationPlugins()
            .flatMap((plugin) => plugin.getExtraDatasourceSpecificationClassifiers?.() ?? []);
        for (const classifier of extraDatasourceSpecificationClassifiers) {
            const type = classifier(spec);
            if (type) {
                return type;
            }
        }
        return undefined;
    }
    get selectedValidDatasources() {
        return (this.editorStore.graphState.findRelationalDatabaseTypeConfiguration(this.connection.type)?.compatibleDataSources ??
            Object.values(CORE_DATASOURCE_SPEC_TYPE).concat(this.editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraDatasourceSpecificationTypes?.() ?? [])));
    }
    get selectedValidAuthenticationStrategies() {
        return (this.editorStore.graphState.findRelationalDatabaseTypeConfiguration(this.connection.type)?.compatibleAuthStrategies ??
            Object.values(CORE_AUTHENTICATION_STRATEGY_TYPE).concat(this.editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraAuthenticationStrategyTypes?.() ?? [])));
    }
    changeDatasourceSpec(type) {
        const observerContext = this.editorStore.changeDetectionState.observerContext;
        let dataSpec;
        switch (type) {
            case CORE_DATASOURCE_SPEC_TYPE.STATIC: {
                dataSpec = new StaticDatasourceSpecification('', 80, '');
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.H2_LOCAL: {
                dataSpec = new LocalH2DatasourceSpecification();
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.H2_EMBEDDED: {
                dataSpec = new EmbeddedH2DatasourceSpecification('', '', false);
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.DATABRICKS: {
                dataSpec = new DatabricksDatasourceSpecification('', '', '', '');
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.SNOWFLAKE: {
                dataSpec = new SnowflakeDatasourceSpecification('', '', '', '');
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.REDSHIFT: {
                dataSpec = new RedshiftDatasourceSpecification('', '', 5439, '', '', '');
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.BIGQUERY: {
                dataSpec = new BigQueryDatasourceSpecification('', '');
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.SPANNER: {
                dataSpec = new SpannerDatasourceSpecification('', '', '', '', '');
                break;
            }
            case CORE_DATASOURCE_SPEC_TYPE.TRINO: {
                dataSpec = new TrinoDatasourceSpecification('', 8090, new TrinoSslSpecification(true));
                break;
            }
            default: {
                const extraDatasourceSpecificationCreators = this.editorStore.pluginManager
                    .getApplicationPlugins()
                    .flatMap((plugin) => plugin.getExtraDatasourceSpecificationCreators?.() ?? []);
                for (const creator of extraDatasourceSpecificationCreators) {
                    const spec = creator(type);
                    if (spec) {
                        dataSpec = spec;
                        break;
                    }
                }
            }
        }
        if (!dataSpec) {
            throw new UnsupportedOperationError(`Can't create datasource specification of type '${type}': no compatible creator available from plugins`);
        }
        relationDbConnection_setDatasourceSpecification(this.connection, dataSpec, observerContext);
        relationDbConnection_setLocalMode(this.connection, this.connection.localMode);
    }
    selectedAuthenticationStrategyType(auth) {
        if (auth instanceof DelegatedKerberosAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.DELEGATED_KERBEROS;
        }
        else if (auth instanceof DefaultH2AuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.H2_DEFAULT;
        }
        else if (auth instanceof OAuthAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.OAUTH;
        }
        else if (auth instanceof ApiTokenAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.API_TOKEN;
        }
        else if (auth instanceof SnowflakePublicAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.SNOWFLAKE_PUBLIC;
        }
        else if (auth instanceof UsernamePasswordAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.USERNAME_PASSWORD;
        }
        else if (auth instanceof GCPApplicationDefaultCredentialsAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.GCP_APPLICATION_DEFAULT_CREDENTIALS;
        }
        else if (auth instanceof GCPWorkloadIdentityFederationAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.GCP_WORKLOAD_IDENTITY_FEDERATION;
        }
        else if (auth instanceof MiddleTierUsernamePasswordAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.MIDDLE_TIER_USERNAME_PASSWORD;
        }
        else if (auth instanceof TrinoDelegatedKerberosAuthenticationStrategy) {
            return CORE_AUTHENTICATION_STRATEGY_TYPE.TRINO_DELEGATED_KERBEROS;
        }
        const extraAuthenticationStrategyClassifiers = this.editorStore.pluginManager
            .getApplicationPlugins()
            .flatMap((plugin) => plugin.getExtraAuthenticationStrategyClassifiers?.() ?? []);
        for (const classifier of extraAuthenticationStrategyClassifiers) {
            const type = classifier(auth);
            if (type) {
                return type;
            }
        }
        return undefined;
    }
    changeAuthenticationStrategy(type) {
        const observerContext = this.editorStore.changeDetectionState.observerContext;
        let authStrategy;
        switch (type) {
            case CORE_AUTHENTICATION_STRATEGY_TYPE.DELEGATED_KERBEROS: {
                authStrategy = new DelegatedKerberosAuthenticationStrategy();
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.API_TOKEN: {
                authStrategy = new ApiTokenAuthenticationStrategy('');
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.SNOWFLAKE_PUBLIC: {
                authStrategy = new SnowflakePublicAuthenticationStrategy('', '', '');
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.GCP_APPLICATION_DEFAULT_CREDENTIALS: {
                authStrategy =
                    new GCPApplicationDefaultCredentialsAuthenticationStrategy();
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.GCP_WORKLOAD_IDENTITY_FEDERATION: {
                authStrategy = new GCPWorkloadIdentityFederationAuthenticationStrategy('', []);
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.H2_DEFAULT: {
                authStrategy = new DefaultH2AuthenticationStrategy();
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.USERNAME_PASSWORD: {
                authStrategy = new UsernamePasswordAuthenticationStrategy('', '');
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.OAUTH: {
                authStrategy = new OAuthAuthenticationStrategy('', '');
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.MIDDLE_TIER_USERNAME_PASSWORD: {
                authStrategy = new MiddleTierUsernamePasswordAuthenticationStrategy('');
                break;
            }
            case CORE_AUTHENTICATION_STRATEGY_TYPE.TRINO_DELEGATED_KERBEROS: {
                authStrategy = new TrinoDelegatedKerberosAuthenticationStrategy('HTTP', false);
                break;
            }
            default: {
                const extraAuthenticationStrategyCreators = this.editorStore.pluginManager
                    .getApplicationPlugins()
                    .flatMap((plugin) => plugin.getExtraAuthenticationStrategyCreators?.() ?? []);
                for (const creator of extraAuthenticationStrategyCreators) {
                    const auth = creator(type);
                    if (auth) {
                        authStrategy = auth;
                        break;
                    }
                }
            }
        }
        if (!authStrategy) {
            throw new UnsupportedOperationError(`Can't create authentication strategy of type '${type}': no compatible creator available from plugins`);
        }
        relationDbConnection_setNewAuthenticationStrategy(this.connection, authStrategy, observerContext);
    }
}
export class JsonModelConnectionValueState extends ConnectionValueState {
    connection;
    constructor(editorStore, connection) {
        super(editorStore, connection);
        this.connection = connection;
    }
    label() {
        return 'Model Connection';
    }
}
export class FlatDataConnectionValueState extends ConnectionValueState {
    connection;
    constructor(editorStore, connection) {
        super(editorStore, connection);
        this.connection = connection;
    }
    label() {
        return 'flat-data connection';
    }
}
export class UnsupportedConnectionValueState extends ConnectionValueState {
    label() {
        return 'unsupported connection';
    }
}
export class ConnectionEditorState {
    /**
     * NOTE: used to force component remount on state change
     */
    uuid = uuid();
    editorStore;
    connection;
    connectionValueState;
    constructor(editorStore, connection) {
        this.editorStore = editorStore;
        this.connection = connection;
        this.connectionValueState = this.buildConnectionValueEditorState();
    }
    buildConnectionValueEditorState() {
        const connection = this.connection;
        if (connection instanceof JsonModelConnection) {
            return new JsonModelConnectionValueState(this.editorStore, connection);
        }
        else if (connection instanceof FlatDataConnection) {
            return new FlatDataConnectionValueState(this.editorStore, connection);
        }
        else if (connection instanceof RelationalDatabaseConnection) {
            return new RelationalDatabaseConnectionValueState(this.editorStore, connection);
        }
        else {
            const extraConnectionValueEditorStateBuilders = this.editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraConnectionValueEditorStateBuilders?.() ?? []);
            for (const stateBuilder of extraConnectionValueEditorStateBuilders) {
                const state = stateBuilder(this.editorStore, connection);
                if (state) {
                    return state;
                }
            }
            return new UnsupportedConnectionValueState(this.editorStore, connection);
        }
    }
}
export class PackageableConnectionEditorState extends ElementEditorState {
    connectionState;
    constructor(editorStore, element) {
        super(editorStore, element);
        makeObservable(this, {
            connection: computed,
            reprocess: action,
        });
        this.connectionState = new ConnectionEditorState(editorStore, this.connection.connectionValue);
    }
    get connection() {
        return guaranteeType(this.element, PackageableConnection, `Element inside connection editor state must be a packageable connection`);
    }
    reprocess(newElement, editorStore) {
        const editorState = new PackageableConnectionEditorState(editorStore, newElement);
        return editorState;
    }
}
//# sourceMappingURL=ConnectionEditorState.js.map