"use strict";
/* ---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// Some code copied and modified from https://github.com/microsoft/vscode/blob/main/src/vs/workbench/api/common/extHostTesting.ts
var _TestRunProfileImpl_proxy, _TestRunProfileImpl_activeProfiles, _TestRunProfileImpl_onDidChangeDefaultProfiles, _TestRunProfileImpl_initialPublish, _TestRunProfileImpl_profiles;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestRunProfileImpl = exports.MirroredTestCollection = exports.TestRunCoordinator = exports.TestRunDto = exports.ExtHostTestsImpl = void 0;
const tslib_1 = require("tslib");
const ide_core_common_1 = require("@opensumi/ide-core-common");
const testCollection_1 = require("@opensumi/ide-testing/lib/common/testCollection");
const testId_1 = require("@opensumi/ide-testing/lib/common/testId");
const vscode_1 = require("../../../common/vscode");
const Convert = tslib_1.__importStar(require("../../../common/vscode/converter"));
const ext_types_1 = require("../../../common/vscode/ext-types");
const testApi_1 = require("../../../common/vscode/testing/testApi");
const testCollection_2 = require("../../../common/vscode/testing/testCollection");
class ExtHostTestsImpl extends ide_core_common_1.Disposable {
    constructor(rpcProtocol) {
        super();
        this.rpcProtocol = rpcProtocol;
        this.resultsChangedEmitter = new ide_core_common_1.Emitter();
        this.controllers = new Map();
        this.defaultProfilesChangedEmitter = this.registerDispose(new ide_core_common_1.Emitter());
        this.debug = (0, ide_core_common_1.getDebugLogger)();
        this.onResultsChanged = this.resultsChangedEmitter.event;
        this.results = [];
        this.proxy = this.rpcProtocol.getProxy(vscode_1.MainThreadAPIIdentifier.MainThreadTests);
        this.runTracker = new TestRunCoordinator(this.proxy);
    }
    // #region API for main thread
    async $runControllerTests(req, token) {
        this.debug.log('do run controller test', req.controllerId, req.profileId, req.testIds);
        const lookup = this.controllers.get(req.controllerId);
        if (!lookup) {
            this.debug.log('can not find any controller', req.controllerId);
            return;
        }
        const { collection, profiles } = lookup;
        const profile = profiles.get(req.profileId);
        if (!profile) {
            return;
        }
        const includeTests = req.testIds.map((testId) => collection.tree.get(testId)).filter(ide_core_common_1.isDefined);
        const excludeTests = req.excludeExtIds
            .map((id) => lookup.collection.tree.get(id))
            .filter(ide_core_common_1.isDefined)
            .filter((exclude) => includeTests.some((include) => include.fullId.compare(exclude.fullId) === 2 /* TestPosition.IsChild */));
        if (!includeTests.length) {
            return;
        }
        const publicReq = new ext_types_1.TestRunRequest(includeTests.some((i) => i.actual instanceof testApi_1.TestItemRootImpl) ? undefined : includeTests.map((t) => t.actual), excludeTests.map((t) => t.actual), profile);
        const tracker = this.runTracker.prepareForMainThreadTestRun(publicReq, TestRunDto.fromInternal(req, lookup.collection), profile, token);
        try {
            await profile.runHandler(publicReq, token);
        }
        finally {
            if (tracker.isRunning && !token.isCancellationRequested) {
                await ide_core_common_1.Event.toPromise(tracker.onEnd);
            }
            tracker.dispose();
        }
    }
    $cancelExtensionTestRun(runId) {
        if (runId === undefined) {
            this.runTracker.cancelAllRuns();
        }
        else {
            this.runTracker.cancelRunById(runId);
        }
    }
    $acceptDiff(diff) {
        this.observer.applyDiff(diff);
    }
    $publishTestResults(results) {
        this.results = Object.freeze(results
            .map((r) => ide_core_common_1.objects.deepFreeze(Convert.TestResults.to(r)))
            .concat(this.results)
            .sort((a, b) => b.completedAt - a.completedAt)
            .slice(0, 32));
        this.resultsChangedEmitter.fire();
    }
    async $expandTest(testId, levels) {
        var _a;
        const collection = (_a = this.controllers.get(testId_1.TestId.fromString(testId).controllerId)) === null || _a === void 0 ? void 0 : _a.collection;
        if (collection) {
            await collection.expand(testId, levels < 0 ? Infinity : levels);
            collection.flushDiff();
        }
    }
    $configureRunProfile(controllerId, profileId) {
        var _a, _b, _c;
        (_c = (_b = (_a = this.controllers.get(controllerId)) === null || _a === void 0 ? void 0 : _a.profiles.get(profileId)) === null || _b === void 0 ? void 0 : _b.configureHandler) === null || _c === void 0 ? void 0 : _c.call(_b);
    }
    async $refreshTests(controllerId, token) {
        var _a, _b, _c;
        await ((_c = (_a = this.controllers.get(controllerId)) === null || _a === void 0 ? void 0 : (_b = _a.controller).refreshHandler) === null || _c === void 0 ? void 0 : _c.call(_b, token));
    }
    // #endregion
    createTestController(controllerId, label, refreshHandler) {
        if (this.controllers.has(controllerId)) {
            throw new Error(`Attempt to insert a duplicate controller with ID "${controllerId}"`);
        }
        const disposable = new ide_core_common_1.DisposableStore();
        const collection = disposable.add(new testCollection_2.SingleUseTestCollection(controllerId));
        collection.root.label = label;
        const profiles = new Map();
        const activeProfiles = new Set();
        const proxy = this.proxy;
        const controller = {
            items: collection.root.children,
            get label() {
                return label;
            },
            set label(value) {
                label = value;
                collection.root.label = value;
                proxy.$updateController(controllerId, { label });
            },
            get refreshHandler() {
                return refreshHandler;
            },
            set refreshHandler(value) {
                refreshHandler = value;
                proxy.$updateController(controllerId, { canRefresh: !!value });
            },
            get id() {
                return controllerId;
            },
            createRunProfile: (label, group, runHandler, isDefault, tag, supportsContinuousRun) => {
                // Derive the profile ID from a hash so that the same profile will tend
                // to have the same hashes, allowing re-run requests to work across reloads.
                let profileId = (0, ide_core_common_1.hash)(label);
                while (profiles.has(profileId)) {
                    profileId++;
                }
                const profile = new TestRunProfileImpl(this.proxy, profiles, activeProfiles, this.defaultProfilesChangedEmitter.event, controllerId, profileId, label, group, runHandler, isDefault, tag, supportsContinuousRun);
                profiles.set(profileId, profile);
                return profile;
            },
            createTestItem(id, label, uri) {
                return new testApi_1.TestItemImpl(controllerId, id, label, uri);
            },
            createTestRun: (request, name, persist = true) => this.runTracker.createTestRun(controllerId, collection, request, name, persist),
            set resolveHandler(fn) {
                collection.resolveHandler = fn;
            },
            get resolveHandler() {
                return collection.resolveHandler;
            },
            invalidateTestResults: (items) => {
                if (items === undefined) {
                    this.proxy.$markTestRetired(undefined);
                }
                else {
                    const itemsArr = items instanceof Array ? items : [items];
                    this.proxy.$markTestRetired(itemsArr.map((i) => testId_1.TestId.fromExtHostTestItem(i, controllerId).toString()));
                }
            },
            dispose: () => {
                disposable.dispose();
            },
        };
        // back compat:
        controller.createRunConfiguration = controller.createRunProfile;
        proxy.$registerTestController(controllerId, label, !!refreshHandler);
        disposable.add((0, ide_core_common_1.toDisposable)(() => proxy.$unregisterTestController(controllerId)));
        const info = { controller, collection, profiles, activeProfiles };
        this.controllers.set(controllerId, info);
        disposable.add((0, ide_core_common_1.toDisposable)(() => this.controllers.delete(controllerId)));
        disposable.add(collection.onDidGenerateDiff((diff) => {
            this.debug.log('ext host test collection did generate diff>>', diff);
            proxy.$publishDiff(controllerId, diff);
        }));
        return controller;
    }
}
exports.ExtHostTestsImpl = ExtHostTestsImpl;
class TestRunDto {
    static fromPublic(controllerId, collection, request, persist) {
        var _a, _b, _c, _d;
        return new TestRunDto(controllerId, (0, ide_core_common_1.uuid)(), (_b = (_a = request.include) === null || _a === void 0 ? void 0 : _a.map((t) => testId_1.TestId.fromExtHostTestItem(t, controllerId).toString())) !== null && _b !== void 0 ? _b : [controllerId], (_d = (_c = request.exclude) === null || _c === void 0 ? void 0 : _c.map((t) => testId_1.TestId.fromExtHostTestItem(t, controllerId).toString())) !== null && _d !== void 0 ? _d : [], persist, collection);
    }
    static fromInternal(request, collection) {
        return new TestRunDto(request.controllerId, request.runId, request.testIds, request.excludeExtIds, true, collection);
    }
    constructor(controllerId, id, include, exclude, isPersisted, colllection) {
        this.controllerId = controllerId;
        this.id = id;
        this.isPersisted = isPersisted;
        this.colllection = colllection;
        this.includePrefix = include.map((id) => id + "\0" /* TestIdPathParts.Delimiter */);
        this.excludePrefix = exclude.map((id) => id + "\0" /* TestIdPathParts.Delimiter */);
    }
    isIncluded(test) {
        const id = testId_1.TestId.fromExtHostTestItem(test, this.controllerId).toString() + "\0" /* TestIdPathParts.Delimiter */;
        for (const prefix of this.excludePrefix) {
            if (id === prefix || id.startsWith(prefix)) {
                return false;
            }
        }
        for (const prefix of this.includePrefix) {
            if (id === prefix || id.startsWith(prefix)) {
                return true;
            }
        }
        return false;
    }
}
exports.TestRunDto = TestRunDto;
class TestRunTracker extends ide_core_common_1.Disposable {
    /**
     * Gets whether there are any tests running.
     */
    get isRunning() {
        return this.tasks.size > 0;
    }
    /**
     * Gets the run ID.
     */
    get id() {
        return this.dto.id;
    }
    constructor(dto, proxy, profile, parentToken) {
        super();
        this.dto = dto;
        this.proxy = proxy;
        this.profile = profile;
        this.state = 0 /* TestRunTrackerState.Running */;
        this.running = 0;
        this.tasks = new Map();
        this.sharedTestIds = new Set();
        this.endEmitter = this.registerDispose(new ide_core_common_1.Emitter());
        this.publishedCoverage = new Map();
        /**
         * Fires when a test ends, and no more tests are left running.
         */
        this.onEnd = this.endEmitter.event;
        this.cts = this.registerDispose(new ide_core_common_1.CancellationTokenSource(parentToken));
        this.registerDispose(this.cts.token.onCancellationRequested(() => {
            for (const { run } of this.tasks.values()) {
                run.end();
            }
        }));
        const didDisposeEmitter = new ide_core_common_1.Emitter();
        this.onDidDispose = didDisposeEmitter.event;
        this.registerDispose((0, ide_core_common_1.toDisposable)(() => {
            didDisposeEmitter.fire();
            didDisposeEmitter.dispose();
        }));
    }
    /** Gets the task ID from a test run object. */
    getTaskIdForRun(run) {
        for (const [taskId, { run: r }] of this.tasks) {
            if (r === run) {
                return taskId;
            }
        }
        return undefined;
    }
    /** Requests cancellation of the run. On the second call, forces cancellation. */
    cancel(taskId) {
        var _a;
        if (taskId) {
            (_a = this.tasks.get(taskId)) === null || _a === void 0 ? void 0 : _a.cts.cancel();
        }
        else if (this.state === 0 /* TestRunTrackerState.Running */) {
            this.cts.cancel();
            this.state = 1 /* TestRunTrackerState.Cancelling */;
        }
        else if (this.state === 1 /* TestRunTrackerState.Cancelling */) {
            this.forciblyEndTasks();
        }
    }
    /** Gets details for a previously-emitted coverage object. */
    async getCoverageDetails(id, testId, token) {
        var _a, _b, _c, _d, _e;
        const [, taskId] = testId_1.TestId.fromString(id).path; /** runId, taskId, URI */
        const coverage = this.publishedCoverage.get(id);
        if (!coverage) {
            return [];
        }
        const { report, extIds } = coverage;
        const task = this.tasks.get(taskId);
        if (!task) {
            throw new Error('unreachable: run task was not found');
        }
        let testItem;
        if (testId && report instanceof ext_types_1.FileCoverage) {
            const index = extIds.indexOf(testId);
            if (index === -1) {
                return []; // ??
            }
            testItem = report.includesTests[index];
        }
        const details = testItem
            ? (_b = (_a = this.profile) === null || _a === void 0 ? void 0 : _a.loadDetailedCoverageForTest) === null || _b === void 0 ? void 0 : _b.call(_a, task.run, report, testItem, token)
            : (_d = (_c = this.profile) === null || _c === void 0 ? void 0 : _c.loadDetailedCoverage) === null || _d === void 0 ? void 0 : _d.call(_c, task.run, report, token);
        return (_e = (await details)) !== null && _e !== void 0 ? _e : [];
    }
    createRun(name) {
        const runId = this.dto.id;
        const ctrlId = this.dto.controllerId;
        const taskId = (0, ide_core_common_1.uuid)();
        const debug = (0, ide_core_common_1.getDebugLogger)();
        const guardTestMutation = (fn) => (test, ...args) => {
            if (ended) {
                debug.warn(`Setting the state of test "${test.id}" is a no-op after the run ends.`);
                return;
            }
            if (!this.dto.isIncluded(test)) {
                return;
            }
            this.ensureTestIsKnown(test);
            fn(test, ...args);
        };
        const appendMessages = (test, messages) => {
            const converted = messages instanceof Array ? messages.map(Convert.TestMessage.from) : [Convert.TestMessage.from(messages)];
            if (test.uri && test.range) {
                const defaultLocation = { range: Convert.Range.from(test.range), uri: test.uri };
                for (const message of converted) {
                    message.location = message.location || defaultLocation;
                }
            }
            this.proxy.$appendTestMessagesInRun(runId, taskId, testId_1.TestId.fromExtHostTestItem(test, ctrlId).toString(), converted);
        };
        let ended = false;
        // tasks are alive for as long as the tracker is alive, so simple this._register is fine:
        const cts = this.registerDispose(new ide_core_common_1.CancellationTokenSource(this.cts.token));
        const run = {
            isPersisted: this.dto.isPersisted,
            token: this.cts.token,
            name,
            onDidDispose: this.onDidDispose,
            // #region state mutation
            /** @stubbed */
            // eslint-disable-next-line @typescript-eslint/no-unused-vars
            addCoverage(fileCoverage) { },
            enqueued: guardTestMutation((test) => {
                this.proxy.$updateTestStateInRun(runId, taskId, testId_1.TestId.fromExtHostTestItem(test, ctrlId).toString(), 1 /* TestResultState.Queued */);
            }),
            skipped: guardTestMutation((test) => {
                this.proxy.$updateTestStateInRun(runId, taskId, testId_1.TestId.fromExtHostTestItem(test, ctrlId).toString(), 5 /* TestResultState.Skipped */);
            }),
            started: guardTestMutation((test) => {
                this.proxy.$updateTestStateInRun(runId, taskId, testId_1.TestId.fromExtHostTestItem(test, ctrlId).toString(), 2 /* TestResultState.Running */);
            }),
            errored: guardTestMutation((test, messages, duration) => {
                appendMessages(test, messages);
                this.proxy.$updateTestStateInRun(runId, taskId, testId_1.TestId.fromExtHostTestItem(test, ctrlId).toString(), 6 /* TestResultState.Errored */, duration);
            }),
            failed: guardTestMutation((test, messages, duration) => {
                appendMessages(test, messages);
                this.proxy.$updateTestStateInRun(runId, taskId, testId_1.TestId.fromExtHostTestItem(test, ctrlId).toString(), 4 /* TestResultState.Failed */, duration);
            }),
            passed: guardTestMutation((test, duration) => {
                this.proxy.$updateTestStateInRun(runId, taskId, testId_1.TestId.fromExtHostTestItem(test, this.dto.controllerId).toString(), 3 /* TestResultState.Passed */, duration);
            }),
            // #endregion
            appendOutput: (output, location, test) => {
                if (ended) {
                    return;
                }
                if (test) {
                    if (this.dto.isIncluded(test)) {
                        this.ensureTestIsKnown(test);
                    }
                    else {
                        test = undefined;
                    }
                }
                this.proxy.$appendOutputToRun(runId, taskId, output, location && Convert.location.from(location), test && testId_1.TestId.fromExtHostTestItem(test, ctrlId).toString());
            },
            end: () => {
                if (ended) {
                    return;
                }
                ended = true;
                this.proxy.$finishedTestRunTask(runId, taskId);
                this.tasks.delete(taskId);
                if (!this.isRunning) {
                    this.dispose();
                }
            },
        };
        this.running++;
        this.tasks.set(taskId, { run, cts });
        this.proxy.$startedTestRunTask(runId, {
            id: taskId,
            ctrlId,
            name,
            running: true,
        });
        return run;
    }
    forciblyEndTasks() {
        for (const { run } of this.tasks.values()) {
            run.end();
        }
    }
    markEnded() {
        if (this.state !== 2 /* TestRunTrackerState.Ended */) {
            this.state = 2 /* TestRunTrackerState.Ended */;
            this.endEmitter.fire();
        }
    }
    dispose() {
        if (!this.disposed) {
            this.markEnded();
            this.cts.cancel();
            super.dispose();
        }
    }
    ensureTestIsKnown(test) {
        if (!(test instanceof testApi_1.TestItemImpl)) {
            throw new testApi_1.InvalidTestItemError(test.id);
        }
        if (this.sharedTestIds.has(testId_1.TestId.fromExtHostTestItem(test, this.dto.controllerId).toString())) {
            return;
        }
        const chain = [];
        const root = this.dto.colllection.root;
        while (true) {
            const converted = Convert.TestItem.from(test);
            chain.unshift(converted);
            if (this.sharedTestIds.has(converted.extId)) {
                break;
            }
            this.sharedTestIds.add(converted.extId);
            if (test === root) {
                break;
            }
            test = test.parent || root;
        }
        this.proxy.$addTestsToRun(this.dto.controllerId, this.dto.id, chain);
    }
}
const tryGetProfileFromTestRunReq = (request) => {
    if (!request.profile) {
        return undefined;
    }
    if (!(request.profile instanceof TestRunProfileImpl)) {
        throw new Error('TestRunRequest.profile is not an instance created from TestController.createRunProfile');
    }
    return request.profile;
};
/**
 * Queues runs for a single extension and provides the currently-executing
 * run so that `createTestRun` can be properly correlated.
 */
class TestRunCoordinator {
    get trackers() {
        return this.tracked.values();
    }
    constructor(proxy) {
        this.proxy = proxy;
        this.tracked = new Map();
    }
    /**
     * Registers a request as being invoked by the main thread, so
     * `$startedExtensionTestRun` is not invoked. The run must eventually
     * be cancelled manually.
     */
    prepareForMainThreadTestRun(req, dto, profile, token) {
        return this.getTracker(req, dto, profile, token);
    }
    /**
     * Cancels an existing test run via its cancellation token.
     */
    cancelRunById(runId) {
        for (const tracker of this.tracked.values()) {
            if (tracker.id === runId) {
                tracker.dispose();
                return;
            }
        }
    }
    /**
     * Cancels an existing test run via its cancellation token.
     */
    cancelAllRuns() {
        for (const tracker of this.tracked.values()) {
            tracker.dispose();
        }
    }
    /**
     * Implements the public `createTestRun` API.
     */
    createTestRun(controllerId, collection, request, name, persist) {
        var _a, _b, _c, _d;
        const existing = this.tracked.get(request);
        if (existing) {
            return existing.createRun(name);
        }
        // If there is not an existing tracked extension for the request, start
        // a new, detached session.
        const dto = TestRunDto.fromPublic(controllerId, collection, request, persist);
        const profile = tryGetProfileFromTestRunReq(request);
        this.proxy.$startedExtensionTestRun({
            controllerId,
            profile: profile && { group: profileGroupToBitset[profile.kind], id: profile.profileId },
            exclude: (_b = (_a = request.exclude) === null || _a === void 0 ? void 0 : _a.map((t) => t.id)) !== null && _b !== void 0 ? _b : [],
            id: dto.id,
            include: (_d = (_c = request.include) === null || _c === void 0 ? void 0 : _c.map((t) => t.id)) !== null && _d !== void 0 ? _d : [collection.root.id],
            persist,
        });
        const tracker = this.getTracker(request, dto, request.profile);
        tracker.onEnd(() => this.proxy.$finishedExtensionTestRun(dto.id));
        return tracker.createRun(name);
    }
    getTracker(req, dto, profile, token) {
        const tracker = new TestRunTracker(dto, this.proxy, profile, token);
        this.tracked.set(req, tracker);
        tracker.onEnd(() => this.tracked.delete(req));
        return tracker;
    }
}
exports.TestRunCoordinator = TestRunCoordinator;
class MirroredChangeCollector extends testCollection_1.IncrementalChangeCollector {
    get isEmpty() {
        return this.added.size === 0 && this.removed.size === 0 && this.updated.size === 0;
    }
    constructor(emitter) {
        super();
        this.emitter = emitter;
        this.added = new Set();
        this.updated = new Set();
        this.removed = new Set();
        this.alreadyRemoved = new Set();
    }
    /**
     * @override
     */
    add(node) {
        this.added.add(node);
    }
    /**
     * @override
     */
    update(node) {
        Object.assign(node.revived, Convert.TestItem.toPlain(node.item));
        if (!this.added.has(node)) {
            this.updated.add(node);
        }
    }
    /**
     * @override
     */
    remove(node) {
        if (this.added.has(node)) {
            this.added.delete(node);
            return;
        }
        this.updated.delete(node);
        if (node.parent && this.alreadyRemoved.has(node.parent)) {
            this.alreadyRemoved.add(node.item.extId);
            return;
        }
        this.removed.add(node);
    }
    /**
     * @override
     */
    getChangeEvent() {
        const { added, updated, removed } = this;
        return {
            get added() {
                return [...added].map((n) => n.revived);
            },
            get updated() {
                return [...updated].map((n) => n.revived);
            },
            get removed() {
                return [...removed].map((n) => n.revived);
            },
        };
    }
    complete() {
        if (!this.isEmpty) {
            this.emitter.fire(this.getChangeEvent());
        }
    }
}
/**
 * Maintains tests in this extension host sent from the main thread.
 * @private
 */
class MirroredTestCollection extends testCollection_1.AbstractIncrementalTestCollection {
    constructor() {
        super(...arguments);
        this.changeEmitter = new ide_core_common_1.Emitter();
        /**
         * Change emitter that fires with the same sematics as `TestObserver.onDidChangeTests`.
         */
        this.onDidChangeTests = this.changeEmitter.event;
    }
    /**
     * Gets a list of root test items.
     */
    get rootTests() {
        return this.roots;
    }
    /**
     *
     * If the test ID exists, returns its underlying ID.
     */
    getMirroredTestDataById(itemId) {
        return this.items.get(itemId);
    }
    /**
     * If the test item is a mirrored test item, returns its underlying ID.
     */
    getMirroredTestDataByReference(item) {
        return this.items.get(item.id);
    }
    /**
     * @override
     */
    createItem(item, parent) {
        return {
            ...item,
            // todo@connor4312: make this work well again with children
            revived: Convert.TestItem.toPlain(item.item),
            depth: parent ? parent.depth + 1 : 0,
            children: new Set(),
        };
    }
    /**
     * @override
     */
    createChangeCollector() {
        return new MirroredChangeCollector(this.changeEmitter);
    }
}
exports.MirroredTestCollection = MirroredTestCollection;
class TestObservers {
    constructor(proxy) {
        this.proxy = proxy;
    }
    checkout() {
        if (!this.current) {
            this.current = this.createObserverData();
        }
        const current = this.current;
        current.observers++;
        return {
            onDidChangeTest: current.tests.onDidChangeTests,
            get tests() {
                return [...current.tests.rootTests].map((t) => t.revived);
            },
            dispose: (0, ide_core_common_1.once)(() => {
                if (--current.observers === 0) {
                    this.proxy.$unsubscribeFromDiffs();
                    this.current = undefined;
                }
            }),
        };
    }
    /**
     * Gets the internal test data by its reference.
     */
    getMirroredTestDataByReference(ref) {
        var _a;
        return (_a = this.current) === null || _a === void 0 ? void 0 : _a.tests.getMirroredTestDataByReference(ref);
    }
    /**
     * Applies test diffs to the current set of observed tests.
     */
    applyDiff(diff) {
        var _a;
        (_a = this.current) === null || _a === void 0 ? void 0 : _a.tests.apply(diff);
    }
    createObserverData() {
        const tests = new MirroredTestCollection();
        this.proxy.$subscribeToDiffs();
        return { observers: 0, tests };
    }
}
const updateProfile = (impl, proxy, initial, update) => {
    if (initial) {
        Object.assign(initial, update);
    }
    else {
        proxy.$updateTestRunConfig(impl.controllerId, impl.profileId, update);
    }
};
class TestRunProfileImpl {
    get label() {
        return this._label;
    }
    set label(label) {
        if (label !== this._label) {
            this._label = label;
            updateProfile(this, tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_proxy, "f"), tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_initialPublish, "f"), { label });
        }
    }
    get supportsContinuousRun() {
        return this._supportsContinuousRun;
    }
    set supportsContinuousRun(supports) {
        if (supports !== this._supportsContinuousRun) {
            this._supportsContinuousRun = supports;
            updateProfile(this, tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_proxy, "f"), tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_initialPublish, "f"), { supportsContinuousRun: supports });
        }
    }
    get isDefault() {
        return tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_activeProfiles, "f").has(this.profileId);
    }
    set isDefault(isDefault) {
        if (isDefault !== this.isDefault) {
            // #activeProfiles is synced from the main thread, so we can make
            // provisional changes here that will get confirmed momentarily
            if (isDefault) {
                tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_activeProfiles, "f").add(this.profileId);
            }
            else {
                tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_activeProfiles, "f").delete(this.profileId);
            }
            updateProfile(this, tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_proxy, "f"), tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_initialPublish, "f"), { isDefault });
        }
    }
    get tag() {
        return this._tag;
    }
    set tag(tag) {
        var _a;
        if ((tag === null || tag === void 0 ? void 0 : tag.id) !== ((_a = this._tag) === null || _a === void 0 ? void 0 : _a.id)) {
            this._tag = tag;
            updateProfile(this, tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_proxy, "f"), tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_initialPublish, "f"), {
                tag: tag ? Convert.TestTag.namespace(this.controllerId, tag.id) : null,
            });
        }
    }
    get configureHandler() {
        return this._configureHandler;
    }
    set configureHandler(handler) {
        if (handler !== this._configureHandler) {
            this._configureHandler = handler;
            updateProfile(this, tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_proxy, "f"), tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_initialPublish, "f"), { hasConfigurationHandler: !!handler });
        }
    }
    get onDidChangeDefault() {
        return ide_core_common_1.Event.chain(tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_onDidChangeDefaultProfiles, "f"), ($) => $.map((ev) => { var _a; return (_a = ev.get(this.controllerId)) === null || _a === void 0 ? void 0 : _a.get(this.profileId); }).filter(ide_core_common_1.isDefined));
    }
    constructor(proxy, profiles, activeProfiles, onDidChangeActiveProfiles, controllerId, profileId, _label, kind, runHandler, _isDefault = false, _tag = undefined, _supportsContinuousRun = false) {
        this.controllerId = controllerId;
        this.profileId = profileId;
        this._label = _label;
        this.kind = kind;
        this.runHandler = runHandler;
        this._tag = _tag;
        this._supportsContinuousRun = _supportsContinuousRun;
        _TestRunProfileImpl_proxy.set(this, void 0);
        _TestRunProfileImpl_activeProfiles.set(this, void 0);
        _TestRunProfileImpl_onDidChangeDefaultProfiles.set(this, void 0);
        _TestRunProfileImpl_initialPublish.set(this, void 0);
        _TestRunProfileImpl_profiles.set(this, void 0);
        tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_proxy, proxy, "f");
        tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_profiles, profiles, "f");
        tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_activeProfiles, activeProfiles, "f");
        tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_onDidChangeDefaultProfiles, onDidChangeActiveProfiles, "f");
        profiles.set(profileId, this);
        const groupBitset = profileGroupToBitset[kind];
        if (typeof groupBitset !== 'number') {
            throw new Error(`Unknown TestRunProfile.group ${kind}`);
        }
        if (_isDefault) {
            activeProfiles.add(profileId);
        }
        tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_initialPublish, {
            profileId,
            controllerId,
            tag: _tag ? Convert.TestTag.namespace(this.controllerId, _tag.id) : null,
            label: _label,
            group: groupBitset,
            isDefault: _isDefault,
            hasConfigurationHandler: false,
            supportsContinuousRun: _supportsContinuousRun, // Main thread not implemented
        }, "f");
        // we send the initial profile publish out on the next microtask so that
        // initially setting the isDefault value doesn't overwrite a user-configured value
        queueMicrotask(() => {
            if (tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_initialPublish, "f")) {
                tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_proxy, "f").$publishTestRunProfile(tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_initialPublish, "f"));
                tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_initialPublish, undefined, "f");
            }
        });
    }
    dispose() {
        var _a;
        if ((_a = tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_profiles, "f")) === null || _a === void 0 ? void 0 : _a.delete(this.profileId)) {
            tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_profiles, undefined, "f");
            tslib_1.__classPrivateFieldGet(this, _TestRunProfileImpl_proxy, "f").$removeTestProfile(this.controllerId, this.profileId);
        }
        tslib_1.__classPrivateFieldSet(this, _TestRunProfileImpl_initialPublish, undefined, "f");
    }
}
exports.TestRunProfileImpl = TestRunProfileImpl;
_TestRunProfileImpl_proxy = new WeakMap(), _TestRunProfileImpl_activeProfiles = new WeakMap(), _TestRunProfileImpl_onDidChangeDefaultProfiles = new WeakMap(), _TestRunProfileImpl_initialPublish = new WeakMap(), _TestRunProfileImpl_profiles = new WeakMap();
const profileGroupToBitset = {
    [ext_types_1.TestRunProfileKind.Coverage]: 8 /* TestRunProfileBitset.Coverage */,
    [ext_types_1.TestRunProfileKind.Debug]: 4 /* TestRunProfileBitset.Debug */,
    [ext_types_1.TestRunProfileKind.Run]: 2 /* TestRunProfileBitset.Run */,
};
//# sourceMappingURL=ext.host.tests.js.map