export const INPUTS: Record<string, unknown> = {};
export const EXPECTED: Record<string, unknown> = {};

INPUTS['number 0'] = 0;
INPUTS['number 1'] = 1;
INPUTS['number nan'] = Number.NaN;
INPUTS['number infinity'] = Number.POSITIVE_INFINITY;
INPUTS['number negative infinity'] = -Number.NEGATIVE_INFINITY;
INPUTS['number epsilon'] = Number.EPSILON;
INPUTS['number int8 max'] = 127;
INPUTS['number int8 min'] = -128;
INPUTS['number int16 max'] = 32767;
INPUTS['number int16 min'] = -32768;
INPUTS['number int32 max'] = 2_147_483_647;
INPUTS['number int32 min'] = -2_147_483_648;
INPUTS['number uint8 max'] = 255;
INPUTS['number 0.1'] = 0.1;
INPUTS['number 0.01'] = 0.01;
INPUTS['number max safe integer'] = Number.MAX_SAFE_INTEGER;
INPUTS['number min safe integer'] = Number.MIN_SAFE_INTEGER;
INPUTS['number max value'] = Number.MAX_VALUE;
INPUTS['number min value'] = Number.MIN_VALUE;

INPUTS['has function'] = {
    value: 1,
    func: () => null,
};
EXPECTED['has function'] = { value: 1 };

INPUTS['function'] = () => null;
EXPECTED['function'] = new Error('Unsupported type Function');

INPUTS['symbol key'] = {
    value: 1,
    [Symbol('key')]: 2,
};
EXPECTED['symbol key'] = { value: 1 };

INPUTS['symbol value'] = {
    value: Symbol('value'),
};
EXPECTED['symbol value'] = new Error('Unsupported type Symbol');

INPUTS['has null'] = {
    value: 1,
    null: null,
};

INPUTS['has undefined'] = {
    value: 1,
    undefined: undefined,
};
EXPECTED['has undefined'] = { value: 1 };

INPUTS['with toJSON'] = new Date(0);
EXPECTED['with toJSON'] = '1970-01-01T00:00:00.000Z';

INPUTS['int8 array'] = new Int8Array([-128, 0, 1, 2, 3, 4, 5, 127]);
INPUTS['uint8 array'] = new Uint8Array([0, 1, 2, 3, 4, 5, 255]);
INPUTS['int16 array'] = new Int16Array([-32768, 0, 1, 2, 3, 4, 5, 32767]);
INPUTS['int32 array'] = new Int32Array([-2_147_483_648, 0, 1, 2, 3, 4, 5, 2_147_483_647]);
INPUTS['bigint64 array'] = new BigInt64Array([
    -9_223_372_036_854_775_808n,
    0n,
    1n,
    2n,
    3n,
    4n,
    5n,
    9_223_372_036_854_775_807n,
]);
INPUTS['float32 array'] = new Float32Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]);
INPUTS['float64 array'] = new Float64Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]);

INPUTS['big int8 array'] = new Int8Array(128 * 1024);
INPUTS['big uint8 array'] = new Uint8Array(128 * 1024);
INPUTS['big int16 array'] = new Int16Array(64 * 1024);
INPUTS['big int32 array'] = new Int32Array(32 * 1024);
INPUTS['big bigint64 array'] = new BigInt64Array(16 * 1024);
INPUTS['big float32 array'] = new Float32Array(32 * 1024);
INPUTS['big float64 array'] = new Float64Array(16 * 1024);

INPUTS['uint8clamp array'] = new Uint8ClampedArray([0, 1, 2, 3, 4, 5, 255]);
EXPECTED['uint8clamp array'] = new Error('Unsupported array buffer view of type Uint8ClampedArray');

INPUTS['typed arrays'] = {
    int8: new Int8Array([-128, 0, 1, 2, 3, 4, 5, 127]),
    uint8: new Uint8Array([0, 1, 2, 3, 4, 5, 255]),
    int16: new Int16Array([-32768, 0, 1, 2, 3, 4, 5, 32767]),
    int32: new Int32Array([-2_147_483_648, 0, 1, 2, 3, 4, 5, 2_147_483_647]),
    bigint64: new BigInt64Array([-9_223_372_036_854_775_808n, 0n, 1n, 2n, 3n, 4n, 5n, 9_223_372_036_854_775_807n]),
    float32: new Float32Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]),
    float64: new Float64Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]),
    int8_big: new Int8Array(128 * 1024),
    uint8_big: new Uint8Array(128 * 1024),
    int16_big: new Int16Array(64 * 1024),
    int32_big: new Int32Array(32 * 1024),
    bigint64_big: new BigInt64Array(16 * 1024),
    float32_big: new Float32Array(32 * 1024),
    float64_big: new Float64Array(16 * 1024),
};

INPUTS['string empty'] = '';
INPUTS['string short ascii'] = 'hello world';
INPUTS['string short 2-byte utf8'] = 'ӒӓӔӕӖӗӘәӚӛӜӝ';
INPUTS['string short 3-byte utf8'] = '你好世界';
INPUTS['string short 4-byte utf8'] = '😀😀😀';
INPUTS['string short 4-byte utf8 unaligned'] = 'a😀😀😀';
INPUTS['string bad surrogate pair'] = 'a\uD800b\uDC00c';
EXPECTED['string bad surrogate pair'] = 'a\uFFFDb\uFFFDc';
INPUTS['string bad high surrogate'] = '\uD800'.repeat(8);
EXPECTED['string bad high surrogate'] = '\uFFFD'.repeat(8);
INPUTS['string bad low surrogate'] = '\uDC00'.repeat(8);
EXPECTED['string bad low surrogate'] = '\uFFFD'.repeat(8);
INPUTS['long string with surrogate pairs'] = '😀'.repeat(128 * 1024);
INPUTS['long string with surrogate pairs unaligned'] = 'a' + '😀'.repeat(128 * 1024) + 'b';
INPUTS['long string bad high surrogate'] = '\uD800'.repeat(128 * 1024);
EXPECTED['long string bad high surrogate'] = '\uFFFD'.repeat(128 * 1024);
INPUTS['long string bad low surrogate'] = '\uDC00'.repeat(128 * 1024);
EXPECTED['long string bad low surrogate'] = '\uFFFD'.repeat(128 * 1024);

INPUTS['huge object'] = Object.fromEntries(
    Array.from({ length: 100_000 }, (_, i) => [
        `key${i}`,
        {
            number: i,
            boolean: i % 2 === 0,
            string: `value${i}`,
            null: null,
        },
    ]),
);

INPUTS['huge array'] = Array.from({ length: 100_000 }, (_, i) => {
    switch (i % 7) {
        case 0:
            return i;
        case 1:
            return i % 2 === 0;
        case 2:
            return `value${i}`;
        case 3:
            return null;
    }
    return undefined;
});
EXPECTED['huge array'] = Array.from({ length: 100_000 }, (_, i) => {
    switch (i % 7) {
        case 0:
            return i;
        case 1:
            return i % 2 === 0;
        case 2:
            return `value${i}`;
    }
    return null;
});

INPUTS['complex object'] = {
    hello: 'world',
    from: ['UBJSON'],
    colors: [[255, 255, 255], [0, 0, 0], [64, 64, 96], new Uint8Array([255, 0, 1, 2, 3, 127])],
    domains: {
        '': '',
        com: 'commercial',
        org: 'organization',
        net: 'network',
    },
    entires: [
        {
            id: 1,
            name: 'test',
            content: null,
            timestamp: 1_532_432_408.008,
            published: false,
        },
        {
            id: 2,
            name: 'lorem',
            content: 'Lorem ipsum...',
            timestamp: 1_532_432_416.346,
            published: true,
        },
    ],
    plots: {
        traces: [
            {
                name: 'test',
                x: new Float64Array([
                    1,
                    2,
                    3,
                    Number.NEGATIVE_INFINITY,
                    Number.POSITIVE_INFINITY,
                    Number.NaN,
                    Number.MAX_VALUE,
                    Number.MIN_VALUE,
                ]),
                y: new Int8Array([0, 4, 5, 6, -128, -1, 127]),
            },
            {
                name: 'test2',
                x: new Float32Array([
                    1,
                    2,
                    3,
                    Number.NEGATIVE_INFINITY,
                    Number.POSITIVE_INFINITY,
                    Number.NaN,
                    Number.MAX_VALUE,
                    Number.MIN_VALUE,
                ]),
                y: new Int16Array([4, 5, 6, -32768, 32767]),
            },
            {
                name: 'test233',
                x: new Int32Array([1, 2, 3, 0, -1]),
                y: new Int32Array([4, 5, 6, -(2 ** 31), 2 ** 31 - 1]),
            },
        ],
    },
    name1: 'short text'.repeat(10),
    name2: 'short text'.repeat(20),
    name3: 'short text'.repeat(30),
    name4: 'short text'.repeat(40),
    name5: 'short text'.repeat(50),
    name6: 'short text'.repeat(60),
    name7: 'short text'.repeat(70),
    name8: 'short text'.repeat(80),
    name9: 'short text'.repeat(90),
    description1: 'medium text'.repeat(100),
    description2: 'medium text'.repeat(200),
    description3: 'medium text'.repeat(500),
    description4: 'medium text'.repeat(1000),
    description5: 'medium text'.repeat(2000),
    description6: 'medium text'.repeat(3000),
    document1: 'long text'.repeat(10000),
    document2: 'long text'.repeat(20000),
    document3: 'long text'.repeat(50000),
    document4: 'long text'.repeat(100_000),
};

INPUTS['cloudpss model'] = {
    rid: 'project/CloudPSS/_SubSysPort',
    name: '模块端口',
    description: '',
    tags: [
        'project:component',
        'type:30000',
        'project-group:模块-基础:101',
        'project-category:component',
        'project-support:job-definition/cloudpss/emtp',
        'project-support:job-definition/cloudpss/sfemt',
        'project-support:job-definition/cloudpss/power-flow',
    ],
    revision: {
        graphic: {
            pins: {
                input: {
                    position: {
                        x: 0.999_999_9,
                        y: 0.5,
                    },
                },
                output: {
                    position: {
                        x: 0,
                        y: 0.5,
                    },
                },
                electrical: {
                    position: {
                        x: 0.999_999_9,
                        y: 0.5,
                    },
                },
            },
            attrs: {
                p0: {
                    fill: 'var(--fill)',
                    stroke: 'var(--stroke)',
                    refPath: {
                        d: 'm90000 0h-60000a10000 10000 0 0 0 0 20000h60000zm0 10000h20000',
                        h: 20000,
                        w: 110_000,
                    },
                    fillOpacity: 'var(--fill-opacity)',
                    strokeWidth: 'var(--stroke-width)',
                    strokeOpacity: 'var(--stroke-opacity)',
                },
                p1: {
                    fill: 'var(--fill)',
                    stroke: 'var(--stroke)',
                    refPath: {
                        d: 'm90000 0h-60000a10000 10000 0 0 0 0 20000h60000zm0 10000h20000',
                        h: 20000,
                        w: 110_000,
                    },
                    fillOpacity: 'var(--fill-opacity)',
                    strokeWidth: 'var(--stroke-width)',
                    strokeOpacity: 'var(--stroke-opacity)',
                },
                p2: {
                    fill: 'transparent',
                    stroke: 'var(--stroke)',
                    refPath: {
                        d: 'm20000 10000m-5000 -5000l5000 5000l-5000 5000',
                        h: 20000,
                        w: 110_000,
                    },
                    fillOpacity: 'var(--fill-opacity)',
                    strokeWidth: 'var(--stroke-width)',
                    strokeOpacity: 'var(--stroke-opacity)',
                },
                p3: {
                    fill: 'var(--fill)',
                    stroke: 'var(--stroke)',
                    refPath: {
                        d: 'm20000 0h60000a10000 10000 0 0 1 0 20000h-60000zm0 10000h-20000',
                        h: 20000,
                        w: 110_000,
                    },
                    fillOpacity: 'var(--fill-opacity)',
                    strokeWidth: 'var(--stroke-width)',
                    strokeOpacity: 'var(--stroke-opacity)',
                },
                p4: {
                    fill: 'transparent',
                    stroke: 'var(--stroke)',
                    refPath: {
                        d: 'm110000 10000m-5000 -5000l5000 5000l-5000 5000',
                        h: 20000,
                        w: 110_000,
                    },
                    fillOpacity: 'var(--fill-opacity)',
                    strokeWidth: 'var(--stroke-width)',
                    strokeOpacity: 'var(--stroke-opacity)',
                },
                t0: {
                    fill: 'var(--spectrum-global-color-orange-600)',
                    refX: 0.5,
                    refY: 0.5,
                    stroke: 'transparent',
                    fontSize: 12,
                    textAnchor: 'middle',
                },
            },
            width: 110,
            height: 20,
            markup: [
                {
                    tagName: 'path',
                    selector: 'p0',
                    condition:
                        "=finder(p, index, array)= equalText(p.key, Key);\n              p = $$.revision.pins.find(finder);\n              p == undefined ? true : (not equalText(p.connection, 'input') and not equalText(p.connection, 'output'))",
                },
                {
                    tagName: 'path',
                    selector: 'p1',
                    condition:
                        "=finder(p, index, array) = equalText(p.key, Key);\n              p = $$.revision.pins.find(finder);\n              p != undefined ? equalText(p.connection, 'input') :false",
                },
                {
                    tagName: 'path',
                    selector: 'p2',
                    condition:
                        "=finder(p, index, array) = equalText(p.key, Key);\n              p = $$.revision.pins.find(finder);\n              p != undefined ? equalText(p.connection, 'output') : false",
                },
                {
                    tagName: 'path',
                    selector: 'p3',
                    condition:
                        "=finder(p, index, array) = equalText(p.key, Key);\n              p = $$.revision.pins.find(finder);\n              p != undefined ? equalText(p.connection, 'output') : false",
                },
                {
                    tagName: 'path',
                    selector: 'p4',
                    condition:
                        "=finder(p, index, array) = equalText(p.key, Key);\n              p = $$.revision.pins.find(finder);\n              p != undefined ? equalText(p.connection, 'input') :false",
                },
                {
                    attrs: {
                        y: '0.35em',
                    },
                    tagName: 'text',
                    selector: 't0',
                    condition: '',
                    textContent: 'Port: $Key',
                },
            ],
            generator: 'x6',
        },
        parameters: [
            {
                name: 'Configuration',
                items: [
                    {
                        key: 'Key',
                        name: 'Pin Key',
                        type: 'choice',
                        value: '',
                        choices:
                            '=mapper(p,index,array) = {key: p.key, name: p.key, description: p.description};\n$$.revision.pins.map(mapper)',
                        condition: 'true',
                        description: '绑定端口',
                    },
                ],
                condition: 'true',
                description: 'Configuration',
            },
        ],
        pins: [
            {
                dim: [
                    "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[1]:''",
                    "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
                ],
                key: 'input',
                data: 'real',
                name: 'Port',
                visible: true,
                condition:
                    "=finder(p, index, array) = equalText(p.key, Key);\np = $$.revision.pins.find(finder);\np != undefined ? equalText(p.connection, 'input') :false",
                connection: 'output',
            },
            {
                dim: [
                    "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
                    "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
                ],
                key: 'output',
                data: 'real',
                name: 'Port',
                visible: true,
                condition:
                    "=finder(p, index, array) = equalText(p.key, Key);\np = $$.revision.pins.find(finder);\np != undefined ? equalText(p.connection, 'output') :false",
                connection: 'input',
            },
            {
                dim: [
                    "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
                    "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
                ],
                key: 'electrical',
                data: 'real',
                name: 'Port',
                visible: true,
                condition:
                    "=finder(p, index, array)= equalText(p.key, Key);\np = $$.revision.pins.find(finder);\np == undefined ? true : (not equalText(p.connection, 'input') and not equalText(p.connection, 'output'))",
                connection: 'electrical',
            },
        ],
        documentation: '@[docs](http://docs.cloudpss.net/components/comp_PSS/comp_PSSSystem/BasicComp/SystemPort)',
    },
};

INPUTS['large array'] = Array.from({ length: 100_000 }).map((_, i) => (i === 12345 ? 'item' : undefined));
EXPECTED['large array'] = Array.from({ length: 100_000 }).map((_, i) => (i === 12345 ? 'item' : null));

INPUTS['object with undefined values'] = { a: 1, b: undefined, c: { d: 2, e: undefined, f: null } };
EXPECTED['object with undefined values'] = { a: 1, c: { d: 2, f: null } };

INPUTS['array with undefined values'] = [1, undefined, 2, undefined, 3];
EXPECTED['array with undefined values'] = [1, null, 2, null, 3];

INPUTS['inject __proto__'] = JSON.parse('{"__proto__": {"a":1}}');
EXPECTED['inject __proto__'] = {};

INPUTS['invalid __proto__'] = JSON.parse('{"__proto__":"xxx"}');
EXPECTED['invalid __proto__'] = {};

INPUTS['null __proto__'] = JSON.parse('{"__proto__":null}');
EXPECTED['null __proto__'] = {};

INPUTS['inject constructor'] = { constructor: { prototype: { a: 1 } } };
INPUTS['invalid constructor prototype'] = { constructor: { prototype: 'xxx' } };
INPUTS['null constructor prototype'] = { constructor: { prototype: null } };
INPUTS['invalid constructor'] = { constructor: 'xxx' };
INPUTS['null constructor'] = { constructor: null };
