
import { URI } from '../../../../base/common/uri.js';
import { Position } from '../../../../editor/common/core/position.js';
import { Range } from '../../../../editor/common/core/range.js';
import { localize } from '../../../../nls.js';
import { TestId } from './testId.js';

var TestResultState;
(function(TestResultState) {
    TestResultState[TestResultState["Unset"] = 0] = "Unset";
    TestResultState[TestResultState["Queued"] = 1] = "Queued";
    TestResultState[TestResultState["Running"] = 2] = "Running";
    TestResultState[TestResultState["Passed"] = 3] = "Passed";
    TestResultState[TestResultState["Failed"] = 4] = "Failed";
    TestResultState[TestResultState["Skipped"] = 5] = "Skipped";
    TestResultState[TestResultState["Errored"] = 6] = "Errored";
})(TestResultState || (TestResultState = {}));
const testResultStateToContextValues = {
    [TestResultState.Unset]: "unset",
    [TestResultState.Queued]: "queued",
    [TestResultState.Running]: "running",
    [TestResultState.Passed]: "passed",
    [TestResultState.Failed]: "failed",
    [TestResultState.Skipped]: "skipped",
    [TestResultState.Errored]: "errored"
};
var ExtTestRunProfileKind;
(function(ExtTestRunProfileKind) {
    ExtTestRunProfileKind[ExtTestRunProfileKind["Run"] = 1] = "Run";
    ExtTestRunProfileKind[ExtTestRunProfileKind["Debug"] = 2] = "Debug";
    ExtTestRunProfileKind[ExtTestRunProfileKind["Coverage"] = 3] = "Coverage";
})(ExtTestRunProfileKind || (ExtTestRunProfileKind = {}));
var TestControllerCapability;
(function(TestControllerCapability) {
    TestControllerCapability[TestControllerCapability["Refresh"] = 2] = "Refresh";
    TestControllerCapability[TestControllerCapability["CodeRelatedToTest"] = 4] = "CodeRelatedToTest";
    TestControllerCapability[TestControllerCapability["TestRelatedToCode"] = 8] = "TestRelatedToCode";
})(TestControllerCapability || (TestControllerCapability = {}));
var TestRunProfileBitset;
(function(TestRunProfileBitset) {
    TestRunProfileBitset[TestRunProfileBitset["Run"] = 2] = "Run";
    TestRunProfileBitset[TestRunProfileBitset["Debug"] = 4] = "Debug";
    TestRunProfileBitset[TestRunProfileBitset["Coverage"] = 8] = "Coverage";
    TestRunProfileBitset[TestRunProfileBitset["HasNonDefaultProfile"] = 16] = "HasNonDefaultProfile";
    TestRunProfileBitset[TestRunProfileBitset["HasConfigurable"] = 32] = "HasConfigurable";
    TestRunProfileBitset[TestRunProfileBitset["SupportsContinuousRun"] = 64] = "SupportsContinuousRun";
})(TestRunProfileBitset || (TestRunProfileBitset = {}));
const testProfileBitset = {
    [TestRunProfileBitset.Run]: ( localize(15487, "Run")),
    [TestRunProfileBitset.Debug]: ( localize(15488, "Debug")),
    [TestRunProfileBitset.Coverage]: ( localize(15489, "Coverage"))
};
const testRunProfileBitsetList = [
    TestRunProfileBitset.Run,
    TestRunProfileBitset.Debug,
    TestRunProfileBitset.Coverage,
    TestRunProfileBitset.HasNonDefaultProfile,
    TestRunProfileBitset.HasConfigurable,
    TestRunProfileBitset.SupportsContinuousRun
];
const isStartControllerTests = t => "runId" in t;
var IRichLocation;
(function(IRichLocation) {
    IRichLocation.serialize = location => ({
        range: location.range.toJSON(),
        uri: location.uri.toJSON()
    });
    IRichLocation.deserialize = (uriIdentity, location) => ({
        range: Range.lift(location.range),
        uri: uriIdentity.asCanonicalUri(URI.revive(location.uri))
    });
})(IRichLocation || (IRichLocation = {}));
var TestMessageType;
(function(TestMessageType) {
    TestMessageType[TestMessageType["Error"] = 0] = "Error";
    TestMessageType[TestMessageType["Output"] = 1] = "Output";
})(TestMessageType || (TestMessageType = {}));
var ITestMessageStackFrame;
(function(ITestMessageStackFrame) {
    ITestMessageStackFrame.serialize = stack => ({
        label: stack.label,
        uri: stack.uri?.toJSON(),
        position: stack.position?.toJSON()
    });
    ITestMessageStackFrame.deserialize = (uriIdentity, stack) => ({
        label: stack.label,
        uri: stack.uri ? uriIdentity.asCanonicalUri(URI.revive(stack.uri)) : undefined,
        position: stack.position ? Position.lift(stack.position) : undefined
    });
})(ITestMessageStackFrame || (ITestMessageStackFrame = {}));
var ITestErrorMessage;
(function(ITestErrorMessage) {
    ITestErrorMessage.serialize = message => ({
        message: message.message,
        type: TestMessageType.Error,
        expected: message.expected,
        actual: message.actual,
        contextValue: message.contextValue,
        location: message.location && IRichLocation.serialize(message.location),
        stackTrace: message.stackTrace?.map(ITestMessageStackFrame.serialize)
    });
    ITestErrorMessage.deserialize = (uriIdentity, message) => ({
        message: message.message,
        type: TestMessageType.Error,
        expected: message.expected,
        actual: message.actual,
        contextValue: message.contextValue,
        location: message.location && IRichLocation.deserialize(uriIdentity, message.location),
        stackTrace: message.stackTrace && ( message.stackTrace.map(s => ITestMessageStackFrame.deserialize(uriIdentity, s)))
    });
})(ITestErrorMessage || (ITestErrorMessage = {}));
const getMarkId = (marker, start) => `${start ? "s" : "e"}${marker}`;
var ITestOutputMessage;
(function(ITestOutputMessage) {
    ITestOutputMessage.serialize = message => ({
        message: message.message,
        type: TestMessageType.Output,
        offset: message.offset,
        length: message.length,
        location: message.location && IRichLocation.serialize(message.location)
    });
    ITestOutputMessage.deserialize = (uriIdentity, message) => ({
        message: message.message,
        type: TestMessageType.Output,
        offset: message.offset,
        length: message.length,
        location: message.location && IRichLocation.deserialize(uriIdentity, message.location)
    });
})(ITestOutputMessage || (ITestOutputMessage = {}));
var ITestMessage;
(function(ITestMessage) {
    ITestMessage.serialize = message => message.type === TestMessageType.Error ? ITestErrorMessage.serialize(message) : ITestOutputMessage.serialize(message);
    ITestMessage.deserialize = (uriIdentity, message) => message.type === TestMessageType.Error ? ITestErrorMessage.deserialize(uriIdentity, message) : ITestOutputMessage.deserialize(uriIdentity, message);
    ITestMessage.isDiffable = message => message.type === TestMessageType.Error && message.actual !== undefined && message.expected !== undefined;
})(ITestMessage || (ITestMessage = {}));
var ITestTaskState;
(function(ITestTaskState) {
    ITestTaskState.serializeWithoutMessages = state => ({
        state: state.state,
        duration: state.duration,
        messages: []
    });
    ITestTaskState.serialize = state => ({
        state: state.state,
        duration: state.duration,
        messages: ( state.messages.map(ITestMessage.serialize))
    });
    ITestTaskState.deserialize = (uriIdentity, state) => ({
        state: state.state,
        duration: state.duration,
        messages: ( state.messages.map(m => ITestMessage.deserialize(uriIdentity, m)))
    });
})(ITestTaskState || (ITestTaskState = {}));
const testTagDelimiter = "\u0000";
const namespaceTestTag = (ctrlId, tagId) => ctrlId + testTagDelimiter + tagId;
const denamespaceTestTag = namespaced => {
    const index = namespaced.indexOf(testTagDelimiter);
    return {
        ctrlId: namespaced.slice(0, index),
        tagId: namespaced.slice(index + 1)
    };
};
var ITestItem;
(function(ITestItem) {
    ITestItem.serialize = item => ({
        extId: item.extId,
        label: item.label,
        tags: item.tags,
        busy: item.busy,
        children: undefined,
        uri: item.uri?.toJSON(),
        range: item.range?.toJSON() || null,
        description: item.description,
        error: item.error,
        sortText: item.sortText
    });
    ITestItem.deserialize = (uriIdentity, serialized) => ({
        extId: serialized.extId,
        label: serialized.label,
        tags: serialized.tags,
        busy: serialized.busy,
        children: undefined,
        uri: serialized.uri ? uriIdentity.asCanonicalUri(URI.revive(serialized.uri)) : undefined,
        range: serialized.range ? Range.lift(serialized.range) : null,
        description: serialized.description,
        error: serialized.error,
        sortText: serialized.sortText
    });
})(ITestItem || (ITestItem = {}));
var TestItemExpandState;
(function(TestItemExpandState) {
    TestItemExpandState[TestItemExpandState["NotExpandable"] = 0] = "NotExpandable";
    TestItemExpandState[TestItemExpandState["Expandable"] = 1] = "Expandable";
    TestItemExpandState[TestItemExpandState["BusyExpanding"] = 2] = "BusyExpanding";
    TestItemExpandState[TestItemExpandState["Expanded"] = 3] = "Expanded";
})(TestItemExpandState || (TestItemExpandState = {}));
var InternalTestItem;
(function(InternalTestItem) {
    InternalTestItem.serialize = item => ({
        expand: item.expand,
        item: ITestItem.serialize(item.item)
    });
    InternalTestItem.deserialize = (uriIdentity, serialized) => ({
        controllerId: TestId.root(serialized.item.extId),
        expand: serialized.expand,
        item: ITestItem.deserialize(uriIdentity, serialized.item)
    });
})(InternalTestItem || (InternalTestItem = {}));
var ITestItemUpdate;
(function(ITestItemUpdate) {
    ITestItemUpdate.serialize = u => {
        let item;
        if (u.item) {
            item = {};
            if (u.item.label !== undefined) {
                item.label = u.item.label;
            }
            if (u.item.tags !== undefined) {
                item.tags = u.item.tags;
            }
            if (u.item.busy !== undefined) {
                item.busy = u.item.busy;
            }
            if (u.item.uri !== undefined) {
                item.uri = u.item.uri?.toJSON();
            }
            if (u.item.range !== undefined) {
                item.range = u.item.range?.toJSON();
            }
            if (u.item.description !== undefined) {
                item.description = u.item.description;
            }
            if (u.item.error !== undefined) {
                item.error = u.item.error;
            }
            if (u.item.sortText !== undefined) {
                item.sortText = u.item.sortText;
            }
        }
        return {
            extId: u.extId,
            expand: u.expand,
            item
        };
    };
    ITestItemUpdate.deserialize = u => {
        let item;
        if (u.item) {
            item = {};
            if (u.item.label !== undefined) {
                item.label = u.item.label;
            }
            if (u.item.tags !== undefined) {
                item.tags = u.item.tags;
            }
            if (u.item.busy !== undefined) {
                item.busy = u.item.busy;
            }
            if (u.item.range !== undefined) {
                item.range = u.item.range ? Range.lift(u.item.range) : null;
            }
            if (u.item.description !== undefined) {
                item.description = u.item.description;
            }
            if (u.item.error !== undefined) {
                item.error = u.item.error;
            }
            if (u.item.sortText !== undefined) {
                item.sortText = u.item.sortText;
            }
        }
        return {
            extId: u.extId,
            expand: u.expand,
            item
        };
    };
})(ITestItemUpdate || (ITestItemUpdate = {}));
const applyTestItemUpdate = (internal, patch) => {
    if (patch.expand !== undefined) {
        internal.expand = patch.expand;
    }
    if (patch.item !== undefined) {
        internal.item = internal.item ? Object.assign(internal.item, patch.item) : patch.item;
    }
};
var TestResultItem;
(function(TestResultItem) {
    TestResultItem.serializeWithoutMessages = original => ({
        ...InternalTestItem.serialize(original),
        ownComputedState: original.ownComputedState,
        computedState: original.computedState,
        tasks: ( original.tasks.map(ITestTaskState.serializeWithoutMessages))
    });
    TestResultItem.serialize = original => ({
        ...InternalTestItem.serialize(original),
        ownComputedState: original.ownComputedState,
        computedState: original.computedState,
        tasks: ( original.tasks.map(ITestTaskState.serialize))
    });
    TestResultItem.deserialize = (uriIdentity, serialized) => ({
        ...InternalTestItem.deserialize(uriIdentity, serialized),
        ownComputedState: serialized.ownComputedState,
        computedState: serialized.computedState,
        tasks: ( serialized.tasks.map(m => ITestTaskState.deserialize(uriIdentity, m))),
        retired: true
    });
})(TestResultItem || (TestResultItem = {}));
var ICoverageCount;
(function(ICoverageCount) {
    ICoverageCount.empty = () => ({
        covered: 0,
        total: 0
    });
    ICoverageCount.sum = (target, src) => {
        target.covered += src.covered;
        target.total += src.total;
    };
})(ICoverageCount || (ICoverageCount = {}));
var IFileCoverage;
(function(IFileCoverage) {
    IFileCoverage.serialize = original => ({
        id: original.id,
        statement: original.statement,
        branch: original.branch,
        declaration: original.declaration,
        testIds: original.testIds,
        uri: original.uri.toJSON()
    });
    IFileCoverage.deserialize = (uriIdentity, serialized) => ({
        id: serialized.id,
        statement: serialized.statement,
        branch: serialized.branch,
        declaration: serialized.declaration,
        testIds: serialized.testIds,
        uri: uriIdentity.asCanonicalUri(URI.revive(serialized.uri))
    });
    IFileCoverage.empty = (id, uri) => ({
        id,
        uri,
        statement: ICoverageCount.empty()
    });
})(IFileCoverage || (IFileCoverage = {}));
function serializeThingWithLocation(serialized) {
    return {
        ...serialized,
        location: serialized.location?.toJSON()
    };
}
function deserializeThingWithLocation(serialized) {
    serialized.location = serialized.location ? (Position.isIPosition(serialized.location) ? Position.lift(serialized.location) : Range.lift(serialized.location)) : undefined;
    return serialized;
}
var DetailType;
(function(DetailType) {
    DetailType[DetailType["Declaration"] = 0] = "Declaration";
    DetailType[DetailType["Statement"] = 1] = "Statement";
    DetailType[DetailType["Branch"] = 2] = "Branch";
})(DetailType || (DetailType = {}));
var CoverageDetails;
(function(CoverageDetails) {
    CoverageDetails.serialize = original => original.type === DetailType.Declaration ? IDeclarationCoverage.serialize(original) : IStatementCoverage.serialize(original);
    CoverageDetails.deserialize = serialized => serialized.type === DetailType.Declaration ? IDeclarationCoverage.deserialize(serialized) : IStatementCoverage.deserialize(serialized);
})(CoverageDetails || (CoverageDetails = {}));
var IBranchCoverage;
(function(IBranchCoverage) {
    IBranchCoverage.serialize = serializeThingWithLocation;
    IBranchCoverage.deserialize = deserializeThingWithLocation;
})(IBranchCoverage || (IBranchCoverage = {}));
var IDeclarationCoverage;
(function(IDeclarationCoverage) {
    IDeclarationCoverage.serialize = serializeThingWithLocation;
    IDeclarationCoverage.deserialize = deserializeThingWithLocation;
})(IDeclarationCoverage || (IDeclarationCoverage = {}));
var IStatementCoverage;
(function(IStatementCoverage) {
    IStatementCoverage.serialize = original => ({
        ...serializeThingWithLocation(original),
        branches: original.branches?.map(IBranchCoverage.serialize)
    });
    IStatementCoverage.deserialize = serialized => ({
        ...deserializeThingWithLocation(serialized),
        branches: serialized.branches?.map(IBranchCoverage.deserialize)
    });
})(IStatementCoverage || (IStatementCoverage = {}));
var TestDiffOpType;
(function(TestDiffOpType) {
    TestDiffOpType[TestDiffOpType["Add"] = 0] = "Add";
    TestDiffOpType[TestDiffOpType["Update"] = 1] = "Update";
    TestDiffOpType[TestDiffOpType["DocumentSynced"] = 2] = "DocumentSynced";
    TestDiffOpType[TestDiffOpType["Remove"] = 3] = "Remove";
    TestDiffOpType[TestDiffOpType["IncrementPendingExtHosts"] = 4] = "IncrementPendingExtHosts";
    TestDiffOpType[TestDiffOpType["Retire"] = 5] = "Retire";
    TestDiffOpType[TestDiffOpType["AddTag"] = 6] = "AddTag";
    TestDiffOpType[TestDiffOpType["RemoveTag"] = 7] = "RemoveTag";
})(TestDiffOpType || (TestDiffOpType = {}));
var TestsDiffOp;
(function(TestsDiffOp) {
    TestsDiffOp.deserialize = (uriIdentity, u) => {
        if (u.op === TestDiffOpType.Add) {
            return {
                op: u.op,
                item: InternalTestItem.deserialize(uriIdentity, u.item)
            };
        } else if (u.op === TestDiffOpType.Update) {
            return {
                op: u.op,
                item: ITestItemUpdate.deserialize(u.item)
            };
        } else if (u.op === TestDiffOpType.DocumentSynced) {
            return {
                op: u.op,
                uri: uriIdentity.asCanonicalUri(URI.revive(u.uri)),
                docv: u.docv
            };
        } else {
            return u;
        }
    };
    TestsDiffOp.serialize = u => {
        if (u.op === TestDiffOpType.Add) {
            return {
                op: u.op,
                item: InternalTestItem.serialize(u.item)
            };
        } else if (u.op === TestDiffOpType.Update) {
            return {
                op: u.op,
                item: ITestItemUpdate.serialize(u.item)
            };
        } else {
            return u;
        }
    };
})(TestsDiffOp || (TestsDiffOp = {}));
class AbstractIncrementalTestCollection {
    constructor(uriIdentity) {
        this.uriIdentity = uriIdentity;
        this._tags = ( new Map());
        this.items = ( new Map());
        this.roots = ( new Set());
        this.busyControllerCount = 0;
        this.pendingRootCount = 0;
        this.tags = this._tags;
    }
    apply(diff) {
        const changes = this.createChangeCollector();
        for (const op of diff) {
            switch (op.op) {
            case TestDiffOpType.Add:
                this.add(InternalTestItem.deserialize(this.uriIdentity, op.item), changes);
                break;
            case TestDiffOpType.Update:
                this.update(ITestItemUpdate.deserialize(op.item), changes);
                break;
            case TestDiffOpType.Remove:
                this.remove(op.itemId, changes);
                break;
            case TestDiffOpType.Retire:
                this.retireTest(op.itemId);
                break;
            case TestDiffOpType.IncrementPendingExtHosts:
                this.updatePendingRoots(op.amount);
                break;
            case TestDiffOpType.AddTag:
                this._tags.set(op.tag.id, op.tag);
                break;
            case TestDiffOpType.RemoveTag:
                this._tags.delete(op.id);
                break;
            }
        }
        changes.complete?.();
    }
    add(item, changes) {
        const parentId = TestId.parentId(item.item.extId)?.toString();
        let created;
        if (!parentId) {
            created = this.createItem(item);
            this.roots.add(created);
            this.items.set(item.item.extId, created);
        } else if (( this.items.has(parentId))) {
            const parent = this.items.get(parentId);
            parent.children.add(item.item.extId);
            created = this.createItem(item, parent);
            this.items.set(item.item.extId, created);
        } else {
            console.error(`Test with unknown parent ID: ${JSON.stringify(item)}`);
            return;
        }
        changes.add?.(created);
        if (item.expand === TestItemExpandState.BusyExpanding) {
            this.busyControllerCount++;
        }
        return created;
    }
    update(patch, changes) {
        const existing = this.items.get(patch.extId);
        if (!existing) {
            return;
        }
        if (patch.expand !== undefined) {
            if (existing.expand === TestItemExpandState.BusyExpanding) {
                this.busyControllerCount--;
            }
            if (patch.expand === TestItemExpandState.BusyExpanding) {
                this.busyControllerCount++;
            }
        }
        applyTestItemUpdate(existing, patch);
        changes.update?.(existing);
        return existing;
    }
    remove(itemId, changes) {
        const toRemove = this.items.get(itemId);
        if (!toRemove) {
            return;
        }
        const parentId = TestId.parentId(toRemove.item.extId)?.toString();
        if (parentId) {
            const parent = this.items.get(parentId);
            parent.children.delete(toRemove.item.extId);
        } else {
            this.roots.delete(toRemove);
        }
        const queue = [[itemId]];
        while (queue.length) {
            for (const itemId of queue.pop()) {
                const existing = this.items.get(itemId);
                if (existing) {
                    queue.push(existing.children);
                    this.items.delete(itemId);
                    changes.remove?.(existing, existing !== toRemove);
                    if (existing.expand === TestItemExpandState.BusyExpanding) {
                        this.busyControllerCount--;
                    }
                }
            }
        }
    }
    retireTest(testId) {}
    updatePendingRoots(delta) {
        this.pendingRootCount += delta;
    }
    createChangeCollector() {
        return {};
    }
}

export { AbstractIncrementalTestCollection, CoverageDetails, DetailType, ExtTestRunProfileKind, IBranchCoverage, ICoverageCount, IDeclarationCoverage, IFileCoverage, IRichLocation, IStatementCoverage, ITestErrorMessage, ITestItem, ITestItemUpdate, ITestMessage, ITestMessageStackFrame, ITestOutputMessage, ITestTaskState, InternalTestItem, TestControllerCapability, TestDiffOpType, TestItemExpandState, TestMessageType, TestResultItem, TestResultState, TestRunProfileBitset, TestsDiffOp, applyTestItemUpdate, denamespaceTestTag, getMarkId, isStartControllerTests, namespaceTestTag, testProfileBitset, testResultStateToContextValues, testRunProfileBitsetList };
