
// Mock only the logger - use real jq-web via require()
// Note: vi.mock('jq-web') does not intercept require() in Vitest ESM mode,
// so we test with the real jq-web WASM module and verify results directly.
vi.mock('../../src/utils/utils', () => ({
  logger: {
    info: vi.fn(),
    debug: vi.fn(),
    warn: vi.fn(),
    error: vi.fn()
  }
}));

import { evaluateJq } from '../../src/lib/jq-resolver';

describe('jq-resolver', () => {
  describe('evaluateJq', () => {
    test('should evaluate simple jq expression', async () => {
      const data = { members: [{ name: 'alice' }, { name: 'bob' }] };

      const result = await evaluateJq(data, '.members');

      expect(result).toEqual([{ name: 'alice' }, { name: 'bob' }]);
    });

    test('should evaluate complex jq expression with pipe and filter', async () => {
      const data = {
        members: [
          { name: 'alice', active: true },
          { name: 'bob', active: false }
        ]
      };

      const result = await evaluateJq(data, '.members | map(select(.active))');

      expect(result).toEqual([{ name: 'alice', active: true }]);
    });

    test('should evaluate nested path expression', async () => {
      const data = { team: { members: [{ name: 'alice' }] } };

      const result = await evaluateJq(data, '.team.members');

      expect(result).toEqual([{ name: 'alice' }]);
    });

    test('should return null when data path does not exist', async () => {
      const data = { foo: 'bar' };

      const result = await evaluateJq(data, '.nonexistent');

      expect(result).toBeNull();
    });

    test('should handle scalar results', async () => {
      const data = { count: 42 };

      const result = await evaluateJq(data, '.count');

      expect(result).toBe(42);
    });

    test('should return null when select() filters out the data', async () => {
      const data = { status: 'completed' };

      const result = await evaluateJq(data, '. | select(.status != "completed") | [.]');

      expect(result).toBeNull();
    });

    test('should return result when select() matches the data', async () => {
      const data = { status: 'active', name: 'task1' };

      const result = await evaluateJq(data, '. | select(.status != "completed") | [.]');

      expect(result).toEqual([{ status: 'active', name: 'task1' }]);
    });

    test('should return null when jq expression is invalid', async () => {
      const data = { foo: 'bar' };

      const result = await evaluateJq(data, '.invalid|||');

      expect(result).toBeNull();
    });
  });

  describe('failure cache', () => {
    test('should cache failures and return null on subsequent calls within TTL', async () => {
      const data = { foo: 'bar' };
      const cacheKey = 'test-file-1';

      // First call: evaluates and fails
      const result1 = await evaluateJq(data, '.invalid|||', cacheKey);
      expect(result1).toBeNull();

      // Second call: should return null from cache without re-evaluating
      const result2 = await evaluateJq(data, '.invalid|||', cacheKey);
      expect(result2).toBeNull();
    });

    test('should not cache failures when cacheKey is not provided', async () => {
      const data = { foo: 'bar' };

      // Both calls should evaluate (no caching without cacheKey)
      const result1 = await evaluateJq(data, '.invalid|||');
      const result2 = await evaluateJq(data, '.invalid|||');
      expect(result1).toBeNull();
      expect(result2).toBeNull();
    });

    test('should use different cache entries for different cacheKeys', async () => {
      const data = { value: 42 };

      // Fail with one key
      await evaluateJq(data, '.invalid|||', 'key-a');

      // Different key with valid expression should still work
      const result = await evaluateJq(data, '.value', 'key-b');
      expect(result).toBe(42);
    });

    test('should use different cache entries for different expressions', async () => {
      const data = { value: 42 };

      // Fail with one expression
      await evaluateJq(data, '.invalid|||', 'same-key');

      // Same key but different (valid) expression should still work
      const result = await evaluateJq(data, '.value', 'same-key');
      expect(result).toBe(42);
    });
  });
});
