"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = void 0;
exports.matchesObject = matchesObject;
exports.anyOf = anyOf;
exports.arrayContaining = arrayContaining;
exports.stringContaining = stringContaining;
exports.objectContaining = objectContaining;
exports.anything = anything;
exports.assertCalledWith = assertCalledWith;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const strict_1 = tslib_1.__importDefault(require("node:assert/strict"));
const node_util_1 = require("node:util");
const ASYMMETRIC_MATCHER = Symbol.for('asymmetricMatcher');
function isAsymmetricMatcher(value) {
    return typeof value === 'object' && value !== null && ASYMMETRIC_MATCHER in value;
}
function deepMatch(actual, expected) {
    if (isAsymmetricMatcher(expected))
        return expected.check(actual);
    if (expected === null || expected === undefined)
        return actual === expected;
    if (typeof expected !== 'object')
        return (0, node_util_1.isDeepStrictEqual)(actual, expected);
    if (Array.isArray(expected)) {
        return Array.isArray(actual) && actual.length === expected.length && expected.every((item, index) => deepMatch(actual[index], item));
    }
    if (typeof actual !== 'object' || actual === null)
        return false;
    return Object.keys(expected).every(key => deepMatch(actual[key], expected[key]));
}
const PrimitiveTypeMap = new Map([
    [Number, 'number'],
    [String, 'string'],
    [Boolean, 'boolean'],
    [BigInt, 'bigint'],
    [Symbol, 'symbol']
]);
function matchesObject(actual, expected) {
    if (!deepMatch(actual, expected)) {
        strict_1.default.fail(`Expected object to match:\n` + `  Expected: ${JSON.stringify(expected, null, 2)}\n` + `  Actual:   ${JSON.stringify(actual, null, 2)}`);
    }
}
function anyOf(Type) {
    const primitiveType = PrimitiveTypeMap.get(Type);
    return {
        [ASYMMETRIC_MATCHER]: true,
        check(value) {
            return primitiveType ? typeof value === primitiveType : value instanceof Type;
        },
        toString() {
            return `any(${Type.name})`;
        }
    };
}
function arrayContaining(expected) {
    return {
        [ASYMMETRIC_MATCHER]: true,
        check(value) {
            return Array.isArray(value) && expected.every(item => value.some(actual => deepMatch(actual, item)));
        },
        toString() {
            return `arrayContaining(${JSON.stringify(expected)})`;
        }
    };
}
function stringContaining(expected) {
    return {
        [ASYMMETRIC_MATCHER]: true,
        check(value) {
            return typeof value === 'string' && value.includes(expected);
        },
        toString() {
            return `stringContaining(${JSON.stringify(expected)})`;
        }
    };
}
function objectContaining(expected) {
    return {
        [ASYMMETRIC_MATCHER]: true,
        check(value) {
            return typeof value === 'object' && value !== null && deepMatch(value, expected);
        },
        toString() {
            return `objectContaining(${JSON.stringify(expected)})`;
        }
    };
}
function anything() {
    return {
        [ASYMMETRIC_MATCHER]: true,
        check() {
            return true;
        },
        toString() {
            return 'anything()';
        }
    };
}
function assertCalledWith(mockFn, ...expectedArgs) {
    const calls = mockFn.mock.calls;
    const match = calls.some(call => call.arguments.length === expectedArgs.length && expectedArgs.every((arg, index) => deepMatch(call.arguments[index], arg)));
    if (!match) {
        strict_1.default.fail(`Expected mock to have been called with:\n` +
            `  Expected: ${JSON.stringify(expectedArgs, null, 2)}\n` +
            `  Actual calls: ${JSON.stringify(calls.map(call => call.arguments), null, 2)}`);
    }
}
exports.__tsfTypeAliases = _a.decodeCompactMetadataV1("[1,{\"AsymmetricMatcher\":{\"kind\":18,\"typeName\":\"AsymmetricMatcher\",\"types\":[],\"index\":{\"kind\":10,\"literal\":true}}}]", []);
//# sourceMappingURL=expect.js.map