"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.constructShellBson = constructShellBson;
const errors_1 = require("@mongosh/errors");
const helpers_1 = require("./helpers");
function constructShellBson({ bsonLibrary: bson, printWarning, assignMetadata, constructHelp, }) {
    const bsonNames = [
        'Binary',
        'Code',
        'DBRef',
        'Decimal128',
        'Double',
        'Int32',
        'Long',
        'MaxKey',
        'MinKey',
        'ObjectId',
        'Timestamp',
        'BSONSymbol',
        'BSONRegExp',
    ];
    const helps = {};
    for (const className of bsonNames) {
        if (!(className in bson)) {
            throw new errors_1.MongoshInternalError(`${className} does not exist in provided BSON package.`);
        }
        const help = constructHelp?.(className);
        helps[className] = help;
        if (!('prototype' in bson[className]))
            continue;
        assignMetadata?.(bson[className].prototype, {
            help: help,
            ...(className === 'BSONSymbol'
                ? { deprecated: true, maxVersion: '1.6.0' }
                : {}),
        });
    }
    const bsonPkg = {
        DBRef: (0, helpers_1.assignAll)(function DBRef(namespace, oid, db, fields) {
            (0, helpers_1.assertArgsDefinedType)([namespace, oid, db], ['string', true, [undefined, 'string'], [undefined, 'object']], 'DBRef');
            return new bson.DBRef(namespace, oid, db, fields);
        }, (0, helpers_1.pickWithExactKeyMatch)(bson.DBRef, ['prototype'])),
        bsonsize: function bsonsize(object) {
            (0, helpers_1.assertArgsDefinedType)([object], ['object'], 'bsonsize');
            return bson.calculateObjectSize(object);
        },
        MaxKey: (0, helpers_1.assignAll)(function MaxKey() {
            return new bson.MaxKey();
        }, (0, helpers_1.pickWithExactKeyMatch)(bson.MaxKey, ['prototype']), { toBSON: () => new bson.MaxKey() }),
        MinKey: (0, helpers_1.assignAll)(function MinKey() {
            return new bson.MinKey();
        }, (0, helpers_1.pickWithExactKeyMatch)(bson.MinKey, ['prototype']), { toBSON: () => new bson.MinKey() }),
        ObjectId: (0, helpers_1.assignAll)(function ObjectId(id) {
            (0, helpers_1.assertArgsDefinedType)([id], [[undefined, 'string', 'number', 'object']], 'ObjectId');
            if (typeof id === 'number')
                return new bson.ObjectId(bson.ObjectId.generate(id));
            return new bson.ObjectId(id);
        }, (0, helpers_1.pickWithExactKeyMatch)(bson.ObjectId, ['prototype', 'cacheHexString', 'generate', 'createFromTime', 'createFromHexString', 'createFromBase64', 'isValid'])),
        Timestamp: (0, helpers_1.assignAll)(function Timestamp(t, i) {
            (0, helpers_1.assertArgsDefinedType)([t, i], [
                ['number', 'object', undefined],
                [undefined, 'number'],
            ], 'Timestamp');
            if (typeof t === 'object' && t !== null && 't' in t && 'i' in t) {
                return new bson.Timestamp(t);
            }
            else if (i !== undefined || typeof t === 'number') {
                return new bson.Timestamp({ t: t, i: i ?? 0 });
            }
            return new bson.Timestamp(t);
        }, (0, helpers_1.pickWithExactKeyMatch)(bson.Timestamp, ['prototype', 'fromInt', 'fromNumber', 'fromBits', 'fromString', 'MAX_VALUE'])),
        Code: (0, helpers_1.assignAll)(function Code(c = '', s) {
            (0, helpers_1.assertArgsDefinedType)([c, s], [
                [undefined, 'string', 'function'],
                [undefined, 'object'],
            ], 'Code');
            return new bson.Code(c, s);
        }, (0, helpers_1.pickWithExactKeyMatch)(bson.Code, ['prototype'])),
        NumberDecimal: (0, helpers_1.assignAll)(function NumberDecimal(s = '0') {
            (0, helpers_1.assertArgsDefinedType)([s], [['string', 'number', 'bson:Long', 'bson:Int32', 'bson:Decimal128']], 'NumberDecimal');
            if (typeof s === 'number') {
                printWarning('NumberDecimal: specifying a number as argument is deprecated and may lead to loss of precision, pass a string instead');
            }
            return bson.Decimal128.fromString(`${s}`);
        }, { prototype: bson.Decimal128.prototype }),
        NumberInt: (0, helpers_1.assignAll)(function NumberInt(v = '0') {
            v ?? (v = '0');
            (0, helpers_1.assertArgsDefinedType)([v], [['string', 'number', 'bson:Long', 'bson:Int32']], 'NumberInt');
            return new bson.Int32(parseInt(`${v}`, 10));
        }, { prototype: bson.Int32.prototype }),
        NumberLong: (0, helpers_1.assignAll)(function NumberLong(s = '0') {
            s ?? (s = '0');
            (0, helpers_1.assertArgsDefinedType)([s], [['string', 'number', 'bson:Long', 'bson:Int32']], 'NumberLong');
            if (typeof s === 'number') {
                printWarning('NumberLong: specifying a number as argument is deprecated and may lead to loss of precision, pass a string instead');
                return bson.Long.fromNumber(s);
            }
            return bson.Long.fromString(`${s}`);
        }, { prototype: bson.Long.prototype }),
        ISODate: function ISODate(input) {
            if (input === undefined)
                return new Date();
            if (typeof input !== 'string')
                return new Date(input);
            const isoDateRegex = /^(?<Y>\d{4})-?(?<M>\d{2})-?(?<D>\d{2})([T ](?<h>\d{2})(:?(?<m>\d{2})(:?((?<s>\d{2})(\.(?<ms>\d+))?))?)?(?<tz>Z|([+-])(\d{2}):?(\d{2})?)?)?$/;
            const match = isoDateRegex.exec(input);
            if (match !== null && match.groups !== undefined) {
                const { Y, M, D, h, m, s, ms, tz } = match.groups;
                const normalized = `${Y}-${M}-${D}T${h || '00'}:${m || '00'}:${s || '00'}.${ms || '000'}${tz || 'Z'}`;
                const date = new Date(normalized);
                if (date.getTime() >= -62167219200000 &&
                    date.getTime() <= 253402300799999) {
                    return date;
                }
            }
            throw new errors_1.MongoshInvalidInputError(`${JSON.stringify(input)} is not a valid ISODate`, errors_1.CommonErrors.InvalidArgument);
        },
        BinData: (0, helpers_1.assignAll)(function BinData(subtype, b64string) {
            (0, helpers_1.assertArgsDefinedType)([subtype, b64string], ['number', 'string'], 'BinData');
            const buffer = Buffer.from(b64string, 'base64');
            return new bson.Binary(buffer, subtype);
        }, { prototype: bson.Binary.prototype }),
        HexData: (0, helpers_1.assignAll)(function HexData(subtype, hexstr) {
            (0, helpers_1.assertArgsDefinedType)([subtype, hexstr], ['number', 'string'], 'HexData');
            const buffer = Buffer.from(hexstr, 'hex');
            return new bson.Binary(buffer, subtype);
        }, { prototype: bson.Binary.prototype }),
        UUID: (0, helpers_1.assignAll)(function UUID(hexstr) {
            if (hexstr === undefined) {
                hexstr = new bson.UUID().toString();
            }
            (0, helpers_1.assertArgsDefinedType)([hexstr], ['string'], 'UUID');
            const buffer = Buffer.from(hexstr.replace(/-/g, ''), 'hex');
            return new bson.Binary(buffer, bson.Binary.SUBTYPE_UUID);
        }, { prototype: bson.Binary.prototype }),
        LegacyJavaUUID: (0, helpers_1.assignAll)(function LegacyJavaUUID(hexstr) {
            if (hexstr === undefined) {
                hexstr = new bson.UUID().toHexString();
            }
            (0, helpers_1.assertArgsDefinedType)([hexstr], ['string'], 'LegacyJavaUUID');
            let hex = String.prototype.replace.call(hexstr, /[{}-]/g, () => '');
            let msb = String.prototype.substring.call(hex, 0, 16);
            let lsb = String.prototype.substring.call(hex, 16, 32);
            msb =
                String.prototype.substring.call(msb, 14, 16) +
                    String.prototype.substring.call(msb, 12, 14) +
                    String.prototype.substring.call(msb, 10, 12) +
                    String.prototype.substring.call(msb, 8, 10) +
                    String.prototype.substring.call(msb, 6, 8) +
                    String.prototype.substring.call(msb, 4, 6) +
                    String.prototype.substring.call(msb, 2, 4) +
                    String.prototype.substring.call(msb, 0, 2);
            lsb =
                String.prototype.substring.call(lsb, 14, 16) +
                    String.prototype.substring.call(lsb, 12, 14) +
                    String.prototype.substring.call(lsb, 10, 12) +
                    String.prototype.substring.call(lsb, 8, 10) +
                    String.prototype.substring.call(lsb, 6, 8) +
                    String.prototype.substring.call(lsb, 4, 6) +
                    String.prototype.substring.call(lsb, 2, 4) +
                    String.prototype.substring.call(lsb, 0, 2);
            hex = msb + lsb;
            const hexBuffer = Buffer.from(hex, 'hex');
            return new bson.Binary(hexBuffer, bson.Binary.SUBTYPE_UUID_OLD);
        }, { prototype: bson.Binary.prototype }),
        LegacyCSharpUUID: (0, helpers_1.assignAll)(function LegacyCSharpUUID(hexstr) {
            if (hexstr === undefined) {
                hexstr = new bson.UUID().toHexString();
            }
            (0, helpers_1.assertArgsDefinedType)([hexstr], ['string'], 'LegacyCSharpUUID');
            let hex = String.prototype.replace.call(hexstr, /[{}-]/g, () => '');
            const a = String.prototype.substring.call(hex, 6, 8) +
                String.prototype.substring.call(hex, 4, 6) +
                String.prototype.substring.call(hex, 2, 4) +
                String.prototype.substring.call(hex, 0, 2);
            const b = String.prototype.substring.call(hex, 10, 12) +
                String.prototype.substring.call(hex, 8, 10);
            const c = String.prototype.substring.call(hex, 14, 16) +
                String.prototype.substring.call(hex, 12, 14);
            const d = String.prototype.substring.call(hex, 16, 32);
            hex = a + b + c + d;
            const hexBuffer = Buffer.from(hex, 'hex');
            return new bson.Binary(hexBuffer, bson.Binary.SUBTYPE_UUID_OLD);
        }, { prototype: bson.Binary.prototype }),
        LegacyPythonUUID: (0, helpers_1.assignAll)(function LegacyPythonUUID(hexstr) {
            if (hexstr === undefined) {
                hexstr = new bson.UUID().toString();
            }
            (0, helpers_1.assertArgsDefinedType)([hexstr], ['string'], 'LegacyPythonUUID');
            const buffer = Buffer.from(hexstr.replace(/-/g, ''), 'hex');
            return new bson.Binary(buffer, bson.Binary.SUBTYPE_UUID_OLD);
        }, { prototype: bson.Binary.prototype }),
        MD5: (0, helpers_1.assignAll)(function MD5(hexstr) {
            (0, helpers_1.assertArgsDefinedType)([hexstr], ['string'], 'MD5');
            const buffer = Buffer.from(hexstr, 'hex');
            return new bson.Binary(buffer, bson.Binary.SUBTYPE_MD5);
        }, { prototype: bson.Binary.prototype }),
        Decimal128: (0, helpers_1.assignAll)((0, helpers_1.functionCtorWithoutProps)(bson.Decimal128), (0, helpers_1.pickWithExactKeyMatch)(bson.Decimal128, [
            'prototype',
            'fromString',
            'fromStringWithRounding',
        ])),
        BSONSymbol: (0, helpers_1.assignAll)((0, helpers_1.functionCtorWithoutProps)(bson.BSONSymbol), (0, helpers_1.pickWithExactKeyMatch)(bson.BSONSymbol, ['prototype'])),
        Int32: (0, helpers_1.assignAll)((0, helpers_1.functionCtorWithoutProps)(bson.Int32), (0, helpers_1.pickWithExactKeyMatch)(bson.Int32, ['prototype', 'fromString'])),
        Long: (0, helpers_1.assignAll)((0, helpers_1.functionCtorWithoutProps)(bson.Long), (0, helpers_1.pickWithExactKeyMatch)(bson.Long, [
            'prototype',
            'fromValue',
            'isLong',
            'fromBytesBE',
            'fromBytesLE',
            'fromBytes',
            'fromString',
            'fromStringStrict',
            'fromBigInt',
            'fromNumber',
            'fromInt',
            'fromBits',
            'MIN_VALUE',
            'MAX_VALUE',
            'NEG_ONE',
            'UONE',
            'ONE',
            'UZERO',
            'ZERO',
            'MAX_UNSIGNED_VALUE',
            'TWO_PWR_24',
        ])),
        Binary: (0, helpers_1.assignAll)((0, helpers_1.functionCtorWithoutProps)(bson.Binary), (0, helpers_1.pickWithExactKeyMatch)(bson.Binary, [
            'prototype',
            'createFromBase64',
            'createFromHexString',
            'fromInt8Array',
            'fromFloat32Array',
            'fromPackedBits',
            'fromBits',
            'BUFFER_SIZE',
            'SUBTYPE_DEFAULT',
            'SUBTYPE_FUNCTION',
            'SUBTYPE_BYTE_ARRAY',
            'SUBTYPE_UUID_OLD',
            'SUBTYPE_UUID',
            'SUBTYPE_MD5',
            'SUBTYPE_ENCRYPTED',
            'SUBTYPE_COLUMN',
            'SUBTYPE_SENSITIVE',
            'SUBTYPE_VECTOR',
            'SUBTYPE_USER_DEFINED',
            'VECTOR_TYPE',
        ])),
        Double: (0, helpers_1.assignAll)((0, helpers_1.functionCtorWithoutProps)(bson.Double), (0, helpers_1.pickWithExactKeyMatch)(bson.Double, ['prototype', 'fromString'])),
        BSONRegExp: (0, helpers_1.assignAll)((0, helpers_1.functionCtorWithoutProps)(bson.BSONRegExp), (0, helpers_1.pickWithExactKeyMatch)(bson.BSONRegExp, ['prototype', 'parseOptions'])),
        EJSON: (0, helpers_1.pickWithExactKeyMatch)(bson.EJSON, [
            'parse',
            'serialize',
            'stringify',
            'deserialize',
        ]),
    };
    for (const className of Object.keys(bsonPkg)) {
        const help = helps[className] ?? constructHelp?.(className);
        if (!help)
            continue;
        bsonPkg[className].help = () => help;
        Object.setPrototypeOf(bsonPkg[className].help, help);
    }
    return bsonPkg;
}
//# sourceMappingURL=shell-bson.js.map