/**
 * 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 { TestExecuted, ServiceTestSuite, TestData, ServiceTest, RunTestsTestableInput, UniqueTestId, DEFAULT_TEST_SUITE_PREFIX, DEFAULT_TEST_PREFIX, TestError, MultiExecutionServiceTestResult, TestExecutionStatus, getAllIdentifiedServiceConnections, } from '@finos/legend-graph';
import { addUniqueEntry, assertErrorThrown, filterByType, ActionState, deleteEntry, isNonNullable, generateEnumerableNameFromToken, guaranteeNonNullable, returnUndefOnError, } from '@finos/legend-shared';
import { action, flow, makeObservable, observable } from 'mobx';
import { service_addConnectionTestData, service_addTest, service_addTestSuite, service_deleteTestSuite, } from '../../../../../graph-modifier/DSL_Service_GraphModifierHelper.js';
import { EmbeddedDataConnectionTypeVisitor, createEmptyEqualToJsonAssertion, } from '../../../../utils/TestableUtils.js';
import { isServiceQueryTDS, } from '../ServiceEditorState.js';
import { ServiceTestDataState, createConnectionTestData, } from './ServiceTestDataState.js';
import { SERIALIZATION_FORMAT, ServiceTestState, } from './ServiceTestEditorState.js';
const createEmptyServiceTestSuite = (serviceTestableState) => {
    // setup
    const serviceEditorState = serviceTestableState.serviceEditorState;
    const service = serviceEditorState.service;
    const suite = new ServiceTestSuite();
    suite.id = generateEnumerableNameFromToken(service.tests.map((s) => s.id), DEFAULT_TEST_SUITE_PREFIX);
    // data
    suite.testData = new TestData();
    const identifiedConnections = getAllIdentifiedServiceConnections(service);
    if (identifiedConnections.length === 1) {
        const connectionVal = guaranteeNonNullable(identifiedConnections[0]);
        const connectionValue = connectionVal.connection;
        const type = returnUndefOnError(() => connectionValue.accept_ConnectionVisitor(new EmbeddedDataConnectionTypeVisitor(serviceEditorState.editorStore)));
        if (type) {
            const testData = createConnectionTestData(connectionVal, type, serviceEditorState.editorStore);
            service_addConnectionTestData(suite, testData, serviceEditorState.editorStore.changeDetectionState.observerContext);
        }
    }
    //
    const test = new ServiceTest();
    test.serializationFormat = isServiceQueryTDS(serviceEditorState.service, serviceEditorState.editorStore)
        ? SERIALIZATION_FORMAT.PURE_TDSOBJECT
        : SERIALIZATION_FORMAT.PURE;
    test.id = generateEnumerableNameFromToken([], DEFAULT_TEST_PREFIX);
    test.__parent = suite;
    suite.tests = [test];
    const assertion = createEmptyEqualToJsonAssertion(test);
    test.assertions = [assertion];
    return suite;
};
export class ServiceTestSuiteState {
    editorStore;
    testableState;
    suite;
    testDataState;
    selectedTestState;
    testStates = [];
    testToRename;
    runningTestState = ActionState.create();
    constructor(suite, testableState) {
        makeObservable(this, {
            editorStore: false,
            testableState: false,
            testToRename: observable,
            selectedTestState: observable,
            setSelectedTestState: action,
            setTestToRename: action,
            addServiceTest: action,
            runSuite: flow,
            runFailingTests: flow,
        });
        this.editorStore = testableState.editorStore;
        this.testableState = testableState;
        this.suite = suite;
        this.testStates = this.suite.tests
            .filter(filterByType(ServiceTest))
            .map((test) => new ServiceTestState(this, test));
        this.selectedTestState = this.testStates[0];
        this.testDataState = this.suite.testData
            ? new ServiceTestDataState(this.suite.testData, this)
            : undefined;
    }
    setTestToRename(test) {
        this.testToRename = test;
    }
    setSelectedTestState(val) {
        this.selectedTestState = val;
    }
    addServiceTest() {
        const test = new ServiceTest();
        test.serializationFormat = SERIALIZATION_FORMAT.PURE;
        test.id = generateEnumerableNameFromToken(this.suite.tests.map((t) => t.id), DEFAULT_TEST_PREFIX);
        test.__parent = this.suite;
        const state = new ServiceTestState(this, test);
        state.addAssertion();
        this.selectedTestState = state;
        service_addTest(this.suite, test);
        addUniqueEntry(this.testStates, state);
    }
    deleteTest(testState) {
        deleteEntry(this.suite.tests, testState.test);
        deleteEntry(this.testStates, testState);
        this.selectedTestState =
            this.selectedTestState === testState
                ? this.testStates[0]
                : this.selectedTestState;
    }
    *runSuite() {
        try {
            this.runningTestState.inProgress();
            this.testStates.forEach((t) => t.resetResult());
            this.testStates.forEach((t) => t.runningTestAction.inProgress());
            const service = this.testableState.serviceEditorState.service;
            const input = new RunTestsTestableInput(service);
            input.unitTestIds = this.suite.tests.map((t) => new UniqueTestId(this.suite, t));
            const testResults = (yield this.editorStore.graphManagerState.graphManager.runTests([input], this.editorStore.graphManagerState.graph));
            testResults.forEach((result) => {
                const state = this.testStates.find((t) => t.test === result.atomicTest);
                state?.handleTestResult(result);
            });
            this.runningTestState.complete();
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
            this.runningTestState.fail();
        }
        finally {
            this.testStates.forEach((t) => t.runningTestAction.complete());
        }
    }
    *runFailingTests() {
        try {
            this.runningTestState.inProgress();
            const service = this.testableState.serviceEditorState.service;
            const input = new RunTestsTestableInput(service);
            input.unitTestIds = this.testStates
                .map((testState) => {
                const result = testState.testResultState.result;
                if ((result instanceof TestExecuted &&
                    result.testExecutionStatus === TestExecutionStatus.FAIL) ||
                    result instanceof TestError) {
                    testState.runningTestAction.inProgress();
                    return new UniqueTestId(this.suite, testState.test);
                }
                return undefined;
            })
                .filter(isNonNullable);
            const testResults = (yield this.editorStore.graphManagerState.graphManager.runTests([input], this.editorStore.graphManagerState.graph));
            testResults.forEach((result) => {
                const state = this.testStates.find((t) => t.test === result.atomicTest);
                state?.handleTestResult(result);
            });
            this.runningTestState.complete();
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
            this.runningTestState.fail();
        }
        finally {
            this.testStates.forEach((t) => t.runningTestAction.complete());
        }
    }
    get testCount() {
        return this.testStates.length;
    }
    get testPassed() {
        return this.testStates.filter((e) => (e.testResultState.result instanceof TestExecuted &&
            e.testResultState.result.testExecutionStatus ===
                TestExecutionStatus.PASS) ||
            (e.testResultState.result instanceof MultiExecutionServiceTestResult &&
                Array.from(e.testResultState.result.keyIndexedTestResults.values()).every((kv) => kv instanceof TestExecuted &&
                    kv.testExecutionStatus === TestExecutionStatus.PASS))).length;
    }
    get testFailed() {
        return this.testStates.filter((e) => (e.testResultState.result instanceof TestExecuted &&
            e.testResultState.result.testExecutionStatus !==
                TestExecutionStatus.PASS) ||
            (e.testResultState.result instanceof MultiExecutionServiceTestResult &&
                Array.from(e.testResultState.result.keyIndexedTestResults.values()).every((kv) => kv instanceof TestExecuted &&
                    kv.testExecutionStatus !== TestExecutionStatus.PASS))).length;
    }
}
export class ServiceTestableState {
    editorStore;
    serviceEditorState;
    selectedSuiteState;
    suiteToRename;
    constructor(editorStore, serviceEditorState) {
        makeObservable(this, {
            editorStore: false,
            serviceEditorState: false,
            selectedSuiteState: observable,
            suiteToRename: observable,
            initSuites: action,
            addTestSuite: action,
            changeSuite: action,
            setSuiteToRename: action,
            deleteSuite: action,
        });
        this.editorStore = editorStore;
        this.serviceEditorState = serviceEditorState;
        this.initSuites();
    }
    get service() {
        return this.serviceEditorState.service;
    }
    setSuiteToRename(testSuite) {
        this.suiteToRename = testSuite;
    }
    deleteSuite(testSuite) {
        service_deleteTestSuite(this.serviceEditorState.service, testSuite);
        if (this.selectedSuiteState?.suite === testSuite) {
            this.selectedSuiteState = this.serviceEditorState.service.tests.length
                ? new ServiceTestSuiteState(this.serviceEditorState.service.tests[0], this)
                : undefined;
        }
    }
    changeSuite(suite) {
        this.selectedSuiteState = new ServiceTestSuiteState(suite, this);
    }
    initSuites() {
        const serviceSuite = this.serviceEditorState.service.tests[0];
        if (serviceSuite instanceof ServiceTestSuite) {
            this.selectedSuiteState = new ServiceTestSuiteState(serviceSuite, this);
        }
        else {
            this.selectedSuiteState = undefined;
        }
    }
    addTestSuite() {
        try {
            const suite = createEmptyServiceTestSuite(this);
            service_addTestSuite(this.serviceEditorState.service, suite, this.serviceEditorState.editorStore.changeDetectionState
                .observerContext);
            this.selectedSuiteState = new ServiceTestSuiteState(suite, this);
        }
        catch (error) {
            assertErrorThrown(error);
            this.editorStore.applicationStore.notificationService.notifyError(`Unable to create service test suite: ${error.message}`);
        }
    }
}
//# sourceMappingURL=ServiceTestableState.js.map