/**
 * Copyright IBM Corp. 2024, 2025
 */
import { AssertionEngine } from '../../../src/engine/assertion/assertion.engine.js';
import { AssertConstants } from '../../../src/constants/assertConstants.js';
import { VCM } from '../../../src/engine/variable-context-manager/context-manager.js';

jest.mock('../../../src/handlers/assertion.handler.js', () => ({
  performAssertion: jest
    .fn()
    .mockImplementation((action: string, actual: any, expected: any) => {
      if (action === AssertConstants.equals_action && actual !== expected) {
        throw new Error('Assertion failed: values are not equal');
      }
      if (
        action === AssertConstants.matches_action &&
        !actual.match(new RegExp(expected))
      ) {
        throw new Error('Assertion failed: values do not match');
      }
      if (
        action === AssertConstants.include_action &&
        !expected.includes(actual)
      ) {
        throw new Error('Assertion failed: values do not include');
      }
      if (
        action === AssertConstants.type_action &&
        typeof actual !== expected
      ) {
        throw new Error('Assertion failed: invalid type');
      }
      if (
        action === AssertConstants.lengthOf_action &&
        actual.length != expected
      ) {
        throw new Error('Assertion failed: length not matching');
      }
      if (
        action === AssertConstants.greaterThan_action &&
        !(actual > expected)
      ) {
        throw new Error('Assertion failed: value is not greater than expected');
      }
      if (action === AssertConstants.lessThan_action && !(actual < expected)) {
        throw new Error('Assertion failed: value is not less than expected');
      }
      if (action === 'invalidAction') {
        throw {};
      }
    }),
}));

describe('AssertionEngine', () => {
  let assertionEngine: AssertionEngine;
  let contextId: string;

  beforeEach(() => {
    contextId = 'contextId';
    assertionEngine = new AssertionEngine();
  });

  describe('assert', () => {
    afterEach(() => {
      VCM.clearAll();
    });

    it('should return an array of RunExecutionAssertion objects', async () => {
      VCM.createContext(contextId).setVariable('status', 200);
      VCM.createContext(contextId).setVariable('responseStatus', 200);
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              if: '${responseStatus} == 200',
              action: AssertConstants.equals_action,
              key: 'status',
              value: 200,
            },
            {
              name: 'test2',
              if: true,
              action: AssertConstants.equals_action,
              key: 'status',
              value: 404,
            },
          ],
        },
      ];
      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      expect(results).toHaveLength(2);
      expect(results[0].assertion).toBe('test1');
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeUndefined();
      expect(results[1].assertion).toBe('test2');
      expect(results[1].skipped).toBeFalsy();
      expect(results[1].error).toEqual({
        message: 'Assertion failed: values are not equal',
        stack: expect.any(String),
        name: 'Error',
        test: 'test2',
      });
    });

    it('should return an array of RunExecutionAssertion objects with conditions and stop on fail', async () => {
      VCM.createContext(contextId).setVariable('status', 200);
      VCM.createContext(contextId).setVariable('responseStatus', 200);
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              action: AssertConstants.equals_action,
              key: 'status',
              value: 200,
            },
            {
              name: 'test2',
              if: '${responseStatus} == 200',
              action: AssertConstants.equals_action,
              key: 'status',
              value: 404,
              stopOnFail: true,
            },
            {
              name: 'test3',
              action: AssertConstants.equals_action,
              key: 'status',
              value: 404,
            },
          ],
        },
      ];
      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      // When test2 fails with stopOnFail=true, remaining assertions are marked as skipped
      expect(results).toHaveLength(3);
      expect(results[0].assertion).toBe('test1');
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeUndefined();
      expect(results[1].assertion).toBe('test2');
      expect(results[1].skipped).toBeFalsy();
      expect(results[1].error).toEqual({
        message: 'Assertion failed: values are not equal',
        stack: expect.any(String),
        name: 'Error',
        test: 'test2',
      });
      // Third test should be marked as skipped
      expect(results[2].assertion).toBe('test3');
      expect(results[2].skipped).toBeTruthy();
      expect(results[2].error).toBeUndefined();
    });

    it('should handle missing keys in the response', async () => {
      VCM.createContext(contextId).setVariable('value', 200);
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              action: AssertConstants.equals_action,
              key: 'nonExistentKey',
              value: 'value',
            },
          ],
        },
      ];
      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      expect(results).toHaveLength(1);
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeDefined();
    });

    it('should perform assertions correctly', async () => {
      VCM.createContext(contextId).setVariable('status', 200);
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              action: AssertConstants.greaterThan_action,
              key: 'status',
              value: 100,
            },
          ],
        },
      ];
      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      expect(results).toHaveLength(1);
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeUndefined();
    });

    it('should perform assert in header values correctly', async () => {
      VCM.createContext(contextId).setVariable('header', {
        'Content-Type': 'application/json',
      });
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              action: AssertConstants.equals_action,
              key: 'header.Content-Type',
              value: 'application/json',
            },
            {
              name: 'test2',
              action: AssertConstants.equals_action,
              key: '${header.Content-Type}',
              value: 'application/json',
            },
            {
              name: 'test3',
              action: AssertConstants.equals_action,
              key: 'header.Content-Type',
              value: 'application/xml',
            },
          ],
        },
      ];

      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      expect(results).toHaveLength(3);
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeUndefined();
      expect(results[1].skipped).toBeFalsy();
      expect(results[1].error).toBeUndefined();
      expect(results[2].skipped).toBeFalsy();
      expect(results[2].error).toBeDefined();
    });

    it('should handle empty error value', async () => {
      VCM.createContext(contextId).setVariable('status', 200);
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              action: 'invalidAction',
              key: 'status',
              value: 'application/json',
            },
          ],
        },
      ];
      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      expect(results).toHaveLength(1);
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeDefined();
    });

    it('should handle variable resolution in value', async () => {
      VCM.createContext(contextId).setVariable('status', 200);
      VCM.createContext(contextId).setVariable('statusCode', 200);
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              action: AssertConstants.equals_action,
              key: 'status',
              value: '${statusCode}',
            },
          ],
        },
      ];
      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      expect(results).toHaveLength(1);
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeUndefined();
    });

    describe('regrex, should validate regrex', () => {
      it('for valid case', async () => {
        VCM.createContext(contextId).setVariable('email', 'test@gmail.com');
        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.matches_action,
                key: 'email',
                value: '[^\s@]+@[^\s@]+\.[^\s@]{2,}',
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(1);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeUndefined();
      });

      it('for invalid case', async () => {
        VCM.createContext(contextId).setVariable('email', 'test.com');
        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.matches_action,
                key: 'email',
                value: '[^\s@]+@[^\s@]+\.[^\s@]{2,}',
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(1);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeDefined();
      });
    });

    it('should match value in array', async () => {
      VCM.createContext(contextId).setVariable('users', [
        { name: 'John', age: 30 },
        { name: 'Jane', age: 25 },
        { name: 'Doe', age: 35 },
      ]);
      const assertions = [
        {
          kind: 'assertion' as const,
          metadata: {
            name: 'basicassert',
            version: 'alpha',
            namespace: 'iam_host_ip',
          },
          spec: [
            {
              name: 'test1',
              action: AssertConstants.include_action,
              key: 'users.1.name',
              value: ['John', 'Jane', 'Doe'],
            },
          ],
        },
      ];
      const request = {
        assertions,
      };

      const [results] = await assertionEngine.assert(request, contextId);

      expect(results).toHaveLength(1);
      expect(results[0].skipped).toBeFalsy();
      expect(results[0].error).toBeUndefined();
    });

    describe('should perform assertion on type of value', () => {
      it('for valid', async () => {
        VCM.createContext(contextId).setVariable('status', 200);
        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.type_action,
                key: 'status',
                value: 'number',
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(1);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeUndefined();
      });

      it('for invalid', async () => {
        VCM.createContext(contextId).setVariable('status', 200);
        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.type_action,
                key: 'status',
                value: 'string',
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(1);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeDefined();
      });
    });

    describe('flat response structures with primitive values', () => {
      it('should assert primitive string values', async () => {
        VCM.createContext(contextId).setVariable('response', {
          name: 'John',
          email: 'john@example.com',
          active: true,
          age: 30,
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'primitiveAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'string_equals',
                action: AssertConstants.equals_action,
                key: 'response.name',
                value: 'John',
              },
              {
                name: 'string_type',
                action: AssertConstants.type_action,
                key: 'response.email',
                value: 'string',
              },
              {
                name: 'boolean_equals',
                action: AssertConstants.equals_action,
                key: 'response.active',
                value: true,
              },
              {
                name: 'number_equals',
                action: AssertConstants.equals_action,
                key: 'response.age',
                value: 30,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(4);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
      });

      it('should handle null and undefined values', async () => {
        VCM.createContext(contextId).setVariable('response', {
          nullValue: null,
          emptyString: '',
          zero: 0,
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'edgeCaseAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'null_check',
                action: AssertConstants.equals_action,
                key: 'response.nullValue',
                value: null,
              },
              {
                name: 'empty_string',
                action: AssertConstants.equals_action,
                key: 'response.emptyString',
                value: '',
              },
              {
                name: 'zero_value',
                action: AssertConstants.equals_action,
                key: 'response.zero',
                value: 0,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
      });
    });

    describe('arrays of simple objects with various property types', () => {
      it('should assert on specific array elements by index', async () => {
        VCM.createContext(contextId).setVariable('users', [
          { name: 'John', age: 30, roles: ['admin', 'user'] },
          { name: 'Jane', age: 25, roles: ['user'] },
          { name: 'Bob', age: 40, roles: ['manager', 'user'] },
        ]);

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'arrayAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'first_user_name',
                action: AssertConstants.equals_action,
                key: 'users.0.name',
                value: 'John',
              },
              {
                name: 'second_user_age',
                action: AssertConstants.equals_action,
                key: 'users.1.age',
                value: 25,
              },
              {
                name: 'third_user_roles',
                action: AssertConstants.lengthOf_action,
                key: 'users.2.roles',
                value: 2,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
      });

      it('should assert on array length', async () => {
        VCM.createContext(contextId).setVariable('products', [
          { id: 1, name: 'Product A', price: 10.99 },
          { id: 2, name: 'Product B', price: 24.99 },
          { id: 3, name: 'Product C', price: 5.99 },
        ]);

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'arrayLengthAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'products_count',
                action: AssertConstants.lengthOf_action,
                key: 'products',
                value: 3,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(1);
        expect(results[0].error).toBeUndefined();
      });
    });

    describe('deeply nested array objects with multiple levels', () => {
      it('should assert on deeply nested array properties', async () => {
        VCM.createContext(contextId).setVariable('organization', {
          departments: [
            {
              name: 'Engineering',
              teams: [
                {
                  name: 'Frontend',
                  members: [
                    { id: 1, name: 'Alice', skills: ['JavaScript', 'React'] },
                    { id: 2, name: 'Bob', skills: ['TypeScript', 'Angular'] },
                  ],
                },
                {
                  name: 'Backend',
                  members: [
                    { id: 3, name: 'Charlie', skills: ['Java', 'Spring'] },
                    { id: 4, name: 'Diana', skills: ['Python', 'Django'] },
                  ],
                },
              ],
            },
            {
              name: 'Marketing',
              teams: [
                {
                  name: 'Digital',
                  members: [
                    { id: 5, name: 'Eve', skills: ['SEO', 'Analytics'] },
                  ],
                },
              ],
            },
          ],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'deepNestedAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'engineering_team_count',
                action: AssertConstants.lengthOf_action,
                key: 'organization.departments.0.teams',
                value: 2,
              },
              {
                name: 'frontend_member_count',
                action: AssertConstants.lengthOf_action,
                key: 'organization.departments.0.teams.0.members',
                value: 2,
              },
              {
                name: 'backend_first_member_name',
                action: AssertConstants.equals_action,
                key: 'organization.departments.0.teams.1.members.0.name',
                value: 'Charlie',
              },
              {
                name: 'marketing_team_member_skills',
                action: AssertConstants.lengthOf_action,
                key: 'organization.departments.1.teams.0.members.0.skills',
                value: 2,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(4);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
      });

      it('should handle arrays with nested arrays', async () => {
        VCM.createContext(contextId).setVariable('matrix', [
          [
            [1, 2, 3],
            [4, 5, 6],
          ],
          [
            [7, 8, 9],
            [10, 11, 12],
          ],
        ]);

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'nestedArrayAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'first_dimension_length',
                action: AssertConstants.lengthOf_action,
                key: 'matrix',
                value: 2,
              },
              {
                name: 'second_dimension_length',
                action: AssertConstants.lengthOf_action,
                key: 'matrix.0',
                value: 2,
              },
              {
                name: 'third_dimension_length',
                action: AssertConstants.lengthOf_action,
                key: 'matrix.0.0',
                value: 3,
              },
              {
                name: 'specific_value',
                action: AssertConstants.equals_action,
                key: 'matrix.1.1.2',
                value: 12,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(4);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
      });
    });

    describe('mixed data structures combining arrays and objects', () => {
      it('should handle complex mixed structures', async () => {
        VCM.createContext(contextId).setVariable('apiResponse', {
          metadata: {
            version: '1.0',
            generated: '2025-01-01',
            status: 'success',
          },
          data: {
            users: [
              {
                id: 1,
                profile: {
                  name: 'John Doe',
                  email: 'john@example.com',
                  preferences: {
                    notifications: true,
                    theme: 'dark',
                  },
                },
                posts: [
                  {
                    id: 101,
                    title: 'First post',
                    comments: [{ author: 'Jane', text: 'Great!' }],
                  },
                  { id: 102, title: 'Second post', comments: [] },
                ],
              },
              {
                id: 2,
                profile: {
                  name: 'Jane Smith',
                  email: 'jane@example.com',
                  preferences: {
                    notifications: false,
                    theme: 'light',
                  },
                },
                posts: [
                  {
                    id: 201,
                    title: 'Hello world',
                    comments: [{ author: 'John', text: 'Nice!' }],
                  },
                ],
              },
            ],
            stats: {
              totalUsers: 2,
              totalPosts: 3,
              activeUsers: ['John Doe', 'Jane Smith'],
            },
          },
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'mixedStructureAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'metadata_version',
                action: AssertConstants.equals_action,
                key: 'apiResponse.metadata.version',
                value: '1.0',
              },
              {
                name: 'user_count',
                action: AssertConstants.lengthOf_action,
                key: 'apiResponse.data.users',
                value: 2,
              },
              {
                name: 'first_user_posts_count',
                action: AssertConstants.lengthOf_action,
                key: 'apiResponse.data.users.0.posts',
                value: 2,
              },
              {
                name: 'second_user_theme',
                action: AssertConstants.equals_action,
                key: 'apiResponse.data.users.1.profile.preferences.theme',
                value: 'light',
              },
              {
                name: 'stats_active_users',
                action: AssertConstants.lengthOf_action,
                key: 'apiResponse.data.stats.activeUsers',
                value: 2,
              },
              {
                name: 'first_user_first_post_comments',
                action: AssertConstants.lengthOf_action,
                key: 'apiResponse.data.users.0.posts.0.comments',
                value: 1,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(6);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
        expect(results[4].error).toBeUndefined();
        expect(results[5].error).toBeUndefined();
      });

      it('should handle objects with array properties and nested objects', async () => {
        VCM.createContext(contextId).setVariable('product', {
          id: 'prod-123',
          name: 'Smartphone',
          variants: [
            {
              color: 'black',
              storage: ['64GB', '128GB'],
              prices: {
                '64GB': { amount: 699, currency: 'USD' },
                '128GB': { amount: 799, currency: 'USD' },
              },
            },
            {
              color: 'white',
              storage: ['64GB', '128GB', '256GB'],
              prices: {
                '64GB': { amount: 699, currency: 'USD' },
                '128GB': { amount: 799, currency: 'USD' },
                '256GB': { amount: 899, currency: 'USD' },
              },
            },
          ],
          reviews: {
            average: 4.5,
            count: 120,
            recent: [
              { user: 'user1', rating: 5, comment: 'Great product!' },
              { user: 'user2', rating: 4, comment: 'Good value' },
            ],
          },
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'productAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'product_name',
                action: AssertConstants.equals_action,
                key: 'product.name',
                value: 'Smartphone',
              },
              {
                name: 'variant_count',
                action: AssertConstants.lengthOf_action,
                key: 'product.variants',
                value: 2,
              },
              {
                name: 'white_variant_storage_options',
                action: AssertConstants.lengthOf_action,
                key: 'product.variants.1.storage',
                value: 3,
              },
              {
                name: 'black_variant_128gb_price',
                action: AssertConstants.equals_action,
                key: 'product.variants.0.prices.128GB.amount',
                value: 799,
              },
              {
                name: 'review_count',
                action: AssertConstants.equals_action,
                key: 'product.reviews.count',
                value: 120,
              },
              {
                name: 'recent_reviews_count',
                action: AssertConstants.lengthOf_action,
                key: 'product.reviews.recent',
                value: 2,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(6);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
        expect(results[4].error).toBeUndefined();
        expect(results[5].error).toBeUndefined();
      });
    });

    describe('edge cases with wildcard syntax', () => {
      it('should handle empty arrays', async () => {
        VCM.createContext(contextId).setVariable('data', {
          emptyArray: [],
          arrayWithEmptyObjects: [{}, {}],
          nestedEmptyArrays: [[], []],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'emptyArrayAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'empty_array_length',
                action: AssertConstants.lengthOf_action,
                key: 'data.emptyArray',
                value: 0,
              },
              {
                name: 'array_with_empty_objects_length',
                action: AssertConstants.lengthOf_action,
                key: 'data.arrayWithEmptyObjects',
                value: 2,
              },
              {
                name: 'nested_empty_arrays_length',
                action: AssertConstants.lengthOf_action,
                key: 'data.nestedEmptyArrays',
                value: 2,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
      });

      it('should handle null values', async () => {
        VCM.createContext(contextId).setVariable('data', {
          nullValue: null,
          objectWithNull: { prop: null },
          arrayWithNulls: [null, 'value', null],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'nullValueAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'direct_null_value',
                action: AssertConstants.equals_action,
                key: 'data.nullValue',
                value: null,
              },
              {
                name: 'object_with_null_prop',
                action: AssertConstants.equals_action,
                key: 'data.objectWithNull.prop',
                value: null,
              },
              {
                name: 'array_with_nulls_length',
                action: AssertConstants.lengthOf_action,
                key: 'data.arrayWithNulls',
                value: 3,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
      });

      it('should handle undefined properties', async () => {
        VCM.createContext(contextId).setVariable('data', {
          definedProp: 'value',
          // undefinedProp is intentionally not defined
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'undefinedPropAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'defined_property',
                action: AssertConstants.equals_action,
                key: 'data.definedProp',
                value: 'value',
              },
              {
                name: 'undefined_property',
                action: AssertConstants.equals_action,
                key: 'data.undefinedProp',
                value: undefined,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(2);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
      });

      it('should handle wildcard on empty or sparse structures', async () => {
        VCM.createContext(contextId).setVariable('data', {
          emptyArray: [],
          sparseArray: [, , { name: 'item' }], // Array with empty slots
          emptyObject: {},
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'wildcardEmptyAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'wildcard_on_empty_array',
                action: AssertConstants.lengthOf_action,
                key: 'data.emptyArray.*',
                value: 0,
              },
              {
                name: 'wildcard_on_sparse_array',
                action: AssertConstants.equals_action,
                key: 'data.sparseArray.2.name',
                value: 'item',
              },
              {
                name: 'wildcard_on_empty_object',
                action: AssertConstants.lengthOf_action,
                key: 'data.emptyObject.*',
                value: 0,
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        // The first assertion might fail depending on implementation - wildcards on empty arrays
        // The third assertion might fail depending on implementation - wildcards on empty objects
        expect(results[1].error).toBeUndefined(); // This should pass
      });
    });

    describe('boundary conditions with wildcard patterns', () => {
      it('should handle wildcards matching different data types', async () => {
        VCM.createContext(contextId).setVariable('mixedData', {
          items: [
            123,
            'string',
            true,
            { key: 'value' },
            [1, 2, 3],
            null,
            undefined,
          ],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'mixedTypesAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'items_length',
                action: AssertConstants.lengthOf_action,
                key: 'mixedData.items',
                value: 7,
              },
              {
                name: 'number_type',
                action: AssertConstants.type_action,
                key: 'mixedData.items.0',
                value: 'number',
              },
              {
                name: 'string_type',
                action: AssertConstants.type_action,
                key: 'mixedData.items.1',
                value: 'string',
              },
              {
                name: 'boolean_type',
                action: AssertConstants.type_action,
                key: 'mixedData.items.2',
                value: 'boolean',
              },
              {
                name: 'object_type',
                action: AssertConstants.type_action,
                key: 'mixedData.items.3',
                value: 'object',
              },
              {
                name: 'array_type',
                action: AssertConstants.type_action,
                key: 'mixedData.items.4',
                value: 'object', // Arrays are objects in JavaScript
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(6);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
        expect(results[4].error).toBeUndefined();
        expect(results[5].error).toBeUndefined();
      });

      it('should handle wildcards with type conversions', async () => {
        VCM.createContext(contextId).setVariable('data', {
          values: [
            '42', // string that looks like a number
            42, // actual number
            'true', // string that looks like a boolean
            true, // actual boolean
            '[]', // string that looks like an array
            [], // actual array
            '{}', // string that looks like an object
            {}, // actual object
          ],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'typeConversionAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'string_number_type',
                action: AssertConstants.type_action,
                key: 'data.values.0',
                value: 'string',
              },
              {
                name: 'actual_number_type',
                action: AssertConstants.type_action,
                key: 'data.values.1',
                value: 'number',
              },
              {
                name: 'string_boolean_type',
                action: AssertConstants.type_action,
                key: 'data.values.2',
                value: 'string',
              },
              {
                name: 'actual_boolean_type',
                action: AssertConstants.type_action,
                key: 'data.values.3',
                value: 'boolean',
              },
              {
                name: 'string_array_type',
                action: AssertConstants.type_action,
                key: 'data.values.4',
                value: 'string',
              },
              {
                name: 'actual_array_type',
                action: AssertConstants.type_action,
                key: 'data.values.5',
                value: 'object',
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(6);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
        expect(results[4].error).toBeUndefined();
        expect(results[5].error).toBeUndefined();
      });

      it('should handle wildcards with edge case values', async () => {
        VCM.createContext(contextId).setVariable('edgeCases', {
          values: [
            0, // falsy number
            '', // empty string
            false, // boolean false
            NaN, // Not a Number
            Infinity, // Infinity
            -Infinity, // Negative Infinity
          ],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'edgeCaseValuesAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'zero_value',
                action: AssertConstants.equals_action,
                key: 'edgeCases.values.0',
                value: 0,
              },
              {
                name: 'empty_string',
                action: AssertConstants.equals_action,
                key: 'edgeCases.values.1',
                value: '',
              },
              {
                name: 'false_value',
                action: AssertConstants.equals_action,
                key: 'edgeCases.values.2',
                value: false,
              },
              // NaN, Infinity and -Infinity tests might be implementation-specific
              // so we're just checking their types
              {
                name: 'nan_type',
                action: AssertConstants.type_action,
                key: 'edgeCases.values.3',
                value: 'number',
              },
              {
                name: 'infinity_type',
                action: AssertConstants.type_action,
                key: 'edgeCases.values.4',
                value: 'number',
              },
              {
                name: 'negative_infinity_type',
                action: AssertConstants.type_action,
                key: 'edgeCases.values.5',
                value: 'number',
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(6);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
        expect(results[3].error).toBeUndefined();
        expect(results[4].error).toBeUndefined();
        expect(results[5].error).toBeUndefined();
      });
    });

    describe('performance with large nested structures', () => {
      it('should handle large arrays efficiently', async () => {
        // Create a large array with 1000 items
        const largeArray = Array.from({ length: 1000 }, (_, i) => ({
          id: i,
          name: `Item ${i}`,
          active: i % 2 === 0,
          tags: [`tag-${i % 10}`, `category-${i % 5}`],
        }));

        VCM.createContext(contextId).setVariable('largeData', {
          items: largeArray,
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'largeArrayAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'array_length',
                action: AssertConstants.lengthOf_action,
                key: 'largeData.items',
                value: 1000,
              },
              {
                name: 'specific_item',
                action: AssertConstants.equals_action,
                key: 'largeData.items.500.id',
                value: 500,
              },
              {
                name: 'last_item',
                action: AssertConstants.equals_action,
                key: 'largeData.items.999.name',
                value: 'Item 999',
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
        expect(results[2].error).toBeUndefined();
      });

      it('should handle deeply nested large structures', async () => {
        // Create a deeply nested structure with multiple levels
        function createNestedStructure(
          depth: number,
          breadth: number,
          currentDepth = 0,
        ): Record<string, any> {
          if (currentDepth >= depth) {
            return { value: `leaf-${currentDepth}-${Math.random()}` };
          }

          const result: Record<string, any> = {};
          for (let i = 0; i < breadth; i++) {
            result[`level${currentDepth}-${i}`] = createNestedStructure(
              depth,
              breadth,
              currentDepth + 1,
            );
          }
          return result;
        }

        // Create a structure with depth 5 and breadth 3 (3^5 = 243 leaf nodes)
        const nestedStructure = createNestedStructure(5, 3);

        VCM.createContext(contextId).setVariable('nestedData', nestedStructure);

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'deepNestedAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'nested_path_exists',
                action: AssertConstants.type_action,
                key: 'nestedData.level0-0.level1-0.level2-0.level3-0.level4-0.value',
                value: 'string',
              },
              {
                name: 'different_nested_path_exists',
                action: AssertConstants.type_action,
                key: 'nestedData.level0-2.level1-1.level2-2.level3-0.level4-1.value',
                value: 'string',
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(2);
        expect(results[0].error).toBeUndefined();
        expect(results[1].error).toBeUndefined();
      });
    });

    describe('negative test cases for wildcard patterns', () => {
      it('should handle non-matching wildcard paths', async () => {
        VCM.createContext(contextId).setVariable('data', {
          users: [
            { name: 'John', role: 'admin' },
            { name: 'Jane', role: 'user' },
          ],
          settings: {
            theme: 'dark',
            notifications: true,
          },
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'nonMatchingWildcardAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'non_existent_wildcard_path',
                action: AssertConstants.lengthOf_action,
                key: 'data.nonexistent.*.name',
                value: 0,
              },
              {
                name: 'wrong_type_for_wildcard',
                action: AssertConstants.lengthOf_action,
                key: 'data.settings.*.property',
                value: 0, // settings is an object, not an array
              },
              {
                name: 'path_beyond_leaf_node',
                action: AssertConstants.equals_action,
                key: 'data.users.0.name.firstname',
                value: 'John', // name is a string, not an object
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        // All of these assertions should fail with appropriate errors
        expect(results[0].error).toBeDefined();
        expect(results[1].error).toBeDefined();
        expect(results[2].error).toBeDefined();
      });

      it('should handle invalid wildcard syntax', async () => {
        VCM.createContext(contextId).setVariable('data', {
          users: [
            { name: 'John', role: 'admin' },
            { name: 'Jane', role: 'user' },
          ],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'invalidWildcardSyntaxAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'multiple_wildcards_together',
                action: AssertConstants.lengthOf_action,
                key: 'data.users.**.name',
                value: 2, // Invalid syntax with ** (should be *)
              },
              {
                name: 'wildcard_at_wrong_position',
                action: AssertConstants.equals_action,
                key: 'data.*.users.name',
                value: 'John', // users is not an array property of multiple objects
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(2);
        // These assertions should fail with appropriate errors
        expect(results[0].error).toBeDefined();
        expect(results[1].error).toBeDefined();
      });

      it('should handle type mismatches in wildcard assertions', async () => {
        VCM.createContext(contextId).setVariable('data', {
          values: [1, 2, 3, 'four', 5],
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'typeMismatchAssert',
              version: 'alpha',
              namespace: 'test',
            },
            spec: [
              {
                name: 'string_comparison_with_number',
                action: AssertConstants.equals_action,
                key: 'data.values.0',
                value: '1', // Type mismatch: 1 (number) vs '1' (string)
              },
              {
                name: 'number_comparison_with_string',
                action: AssertConstants.equals_action,
                key: 'data.values.3',
                value: 4, // Type mismatch: 'four' (string) vs 4 (number)
              },
            ],
          },
        ];
        const request = { assertions };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(2);
        // These assertions should fail due to type mismatches
        expect(results[0].error).toBeDefined();
        expect(results[1].error).toBeDefined();
      });
    });

    describe('should resolve wildcard keys for', () => {
      it('one array - content validation with wildcards', async () => {
        VCM.createContext(contextId).setVariable('users', [
          { name: 'John', age: 30 },
          { name: 'Jane', age: 25 },
          { name: 'Doe', age: 35 },
        ]);

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.type_action,
                key: 'users.*.name',
                value: 'string',
              },
              {
                name: 'test2',
                action: AssertConstants.include_action,
                key: 'users.0.name',
                value: ['John', 'Jane', 'Doe'],
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(2);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeUndefined();
        expect(results[1].skipped).toBeFalsy();
        expect(results[1].error).toBeUndefined();
      });

      it('deep array - content validation with wildcards', async () => {
        VCM.createContext(contextId).setVariable('users', [
          { name: 'John', age: 30, id: [{ uuid: 'abc' }] },
          { name: 'Jane', age: 25, id: [{ uuid: 'def' }] },
          { name: 'Doe', age: 35 },
        ]);

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.type_action,
                key: 'users.*.id.*.uuid',
                value: 'string',
              },
              {
                name: 'test2',
                action: AssertConstants.include_action,
                key: 'users.1.id.0.uuid',
                value: ['abc', 'def', 'ghi'],
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(2);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeUndefined();
        expect(results[1].skipped).toBeFalsy();
        expect(results[1].error).toBeUndefined();
      });

      it('object level - property validation with wildcards', async () => {
        VCM.createContext(contextId).setVariable('users', {
          name: {
            a: { id: 1 },
            b: { id: 2 },
          },
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.type_action,
                key: 'users.name.*.id',
                value: 'number',
              },
              {
                name: 'test2',
                action: AssertConstants.greaterThan_action,
                key: 'users.name.b.id',
                value: 1,
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(2);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeUndefined();
        expect(results[1].skipped).toBeFalsy();
        expect(results[1].error).toBeUndefined();
      });

      it('deep object level - value integrity with wildcards', async () => {
        VCM.createContext(contextId).setVariable('users', {
          a: {
            name: {
              x: { id: 1 },
              y: { id: 2 },
            },
          },
          b: {
            name: {
              z: { id: 3 },
            },
          },
        });

        const assertions = [
          {
            kind: 'assertion' as const,
            metadata: {
              name: 'basicassert',
              version: 'alpha',
              namespace: 'iam_host_ip',
            },
            spec: [
              {
                name: 'test1',
                action: AssertConstants.type_action,
                key: 'users.*.name.*.id',
                value: 'number',
              },
              {
                name: 'test2',
                action: AssertConstants.greaterThan_action,
                key: 'users.b.name.z.id',
                value: 2,
              },
              {
                name: 'test3',
                action: AssertConstants.lessThan_action,
                key: 'users.a.name.x.id',
                value: 2,
              },
            ],
          },
        ];
        const request = {
          assertions,
        };

        const [results] = await assertionEngine.assert(request, contextId);

        expect(results).toHaveLength(3);
        expect(results[0].skipped).toBeFalsy();
        expect(results[0].error).toBeUndefined();
        expect(results[1].skipped).toBeFalsy();
        expect(results[1].error).toBeUndefined();
        expect(results[2].skipped).toBeFalsy();
        expect(results[2].error).toBeUndefined();
      });
    });
  });
});
