import { VariableResolver } from '../variable-resolver.js';

describe('VariableResolver', () => {
  let resolver: VariableResolver;
  
  beforeEach(() => {
    resolver = new VariableResolver();
  });
  
  describe('resolveVariables', () => {
    it('should resolve simple string variables', async () => {
      const input = 'Hello ${name}, welcome to ${place}!';
      const context = { name: 'John', place: 'Atlas' };
      
      const result = await resolver.resolveVariables(input, context);
      
      expect(result).toBe('Hello John, welcome to Atlas!');
    });
    
    it('should handle missing variables', async () => {
      const input = 'Hello ${name}, your score is ${score}';
      const context = { name: 'Alice' }; // score is missing
      
      const result = await resolver.resolveVariables(input, context);
      
      expect(result).toBe('Hello Alice, your score is ${score}');
    });
    
    it('should resolve nested object paths', async () => {
      const input = 'User ${user.name} from ${user.address.city}';
      const context = {
        user: {
          name: 'Bob',
          address: {
            city: 'New York',
            country: 'USA'
          }
        }
      };
      
      const result = await resolver.resolveVariables(input, context);
      
      expect(result).toBe('User Bob from New York');
    });
    
    it('should resolve variables in objects', async () => {
      const input = {
        greeting: 'Hello ${name}',
        message: 'Your balance is ${balance}',
        nested: {
          info: 'Location: ${location}'
        }
      };
      const context = { name: 'Charlie', balance: 100, location: 'SF' };
      
      const result = await resolver.resolveVariables(input, context);
      
      expect(result).toEqual({
        greeting: 'Hello Charlie',
        message: 'Your balance is 100',
        nested: {
          info: 'Location: SF'
        }
      });
    });
    
    it('should resolve variables in arrays', async () => {
      const input = ['Hello ${name}', 'Score: ${score}', { msg: '${message}' }];
      const context = { name: 'Dave', score: 42, message: 'Well done!' };
      
      const result = await resolver.resolveVariables(input, context);
      
      expect(result).toEqual(['Hello Dave', 'Score: 42', { msg: 'Well done!' }]);
    });
    
    it('should handle non-string primitives', async () => {
      const input = { num: 42, bool: true, nil: null };
      const context = {};
      
      const result = await resolver.resolveVariables(input, context);
      
      expect(result).toEqual({ num: 42, bool: true, nil: null });
    });
    
    it('should handle complex nested structures', async () => {
      const input = {
        users: [
          { name: '${users.0.name}', role: '${users.0.role}' },
          { name: '${users.1.name}', role: '${users.1.role}' }
        ],
        config: {
          api: {
            url: '${env.apiUrl}',
            key: '${env.apiKey}'
          }
        }
      };
      
      const context = {
        users: [
          { name: 'Admin', role: 'administrator' },
          { name: 'User', role: 'member' }
        ],
        env: {
          apiUrl: 'https://api.example.com',
          apiKey: 'secret-key'
        }
      };
      
      const result = await resolver.resolveVariables(input, context);
      
      expect(result).toEqual({
        users: [
          { name: 'Admin', role: 'administrator' },
          { name: 'User', role: 'member' }
        ],
        config: {
          api: {
            url: 'https://api.example.com',
            key: 'secret-key'
          }
        }
      });
    });
  });
  
  describe('evaluateCondition', () => {
    it('should evaluate equality conditions', async () => {
      const context = { status: 'active', count: 5 };
      
      expect(await resolver.evaluateCondition('status == active', context)).toBe(true);
      expect(await resolver.evaluateCondition('status === active', context)).toBe(true);
      expect(await resolver.evaluateCondition('status == inactive', context)).toBe(false);
      expect(await resolver.evaluateCondition('count == 5', context)).toBe(true);
    });
    
    it('should evaluate inequality conditions', async () => {
      const context = { status: 'active', count: 5 };
      
      expect(await resolver.evaluateCondition('status != inactive', context)).toBe(true);
      expect(await resolver.evaluateCondition('status !== inactive', context)).toBe(true);
      expect(await resolver.evaluateCondition('count != 10', context)).toBe(true);
    });
    
    it('should evaluate comparison conditions', async () => {
      const context = { count: 5, price: 99.99 };
      
      expect(await resolver.evaluateCondition('count > 3', context)).toBe(true);
      expect(await resolver.evaluateCondition('count >= 5', context)).toBe(true);
      expect(await resolver.evaluateCondition('count < 10', context)).toBe(true);
      expect(await resolver.evaluateCondition('count <= 5', context)).toBe(true);
      expect(await resolver.evaluateCondition('price > 100', context)).toBe(false);
    });
    
    it('should evaluate boolean literals', async () => {
      const context = {};
      
      expect(await resolver.evaluateCondition('true', context)).toBe(true);
      expect(await resolver.evaluateCondition('false', context)).toBe(false);
    });
    
    it('should evaluate variable existence', async () => {
      const context = { hasFeature: true, emptyValue: '', zero: 0 };
      
      expect(await resolver.evaluateCondition('hasFeature', context)).toBe(true);
      expect(await resolver.evaluateCondition('missingVar', context)).toBe(false);
      expect(await resolver.evaluateCondition('emptyValue', context)).toBe(false);
      expect(await resolver.evaluateCondition('zero', context)).toBe(false); // 0 is falsy
    });
    
    it('should resolve variables in conditions', async () => {
      const context = { 
        user: { role: 'admin' },
        threshold: 10,
        value: 15
      };
      
      expect(await resolver.evaluateCondition('${user.role} == admin', context)).toBe(true);
      expect(await resolver.evaluateCondition('${value} > ${threshold}', context)).toBe(true);
    });
    
    it('should handle string comparisons with quotes', async () => {
      const context = { message: 'hello world' };
      
      expect(await resolver.evaluateCondition('message == "hello world"', context)).toBe(true);
      expect(await resolver.evaluateCondition("message == 'hello world'", context)).toBe(true);
      expect(await resolver.evaluateCondition('message == "goodbye"', context)).toBe(false);
    });
    
    it('should handle numeric comparisons', async () => {
      const context = { strNum: '42', actualNum: 42 };
      
      expect(await resolver.evaluateCondition('strNum > 40', context)).toBe(true);
      expect(await resolver.evaluateCondition('actualNum > 40', context)).toBe(true);
    });
    
    it('should handle complex expressions with variables', async () => {
      const context = {
        order: { total: 150, discount: 20 },
        user: { isPremium: true }
      };
      
      const condition = '${order.total} > 100';
      expect(await resolver.evaluateCondition(condition, context)).toBe(true);
    });
    
    it('should return false for malformed conditions', async () => {
      const context = { value: 10 };
      
      expect(await resolver.evaluateCondition('invalid expression @#$', context)).toBe(false);
      expect(await resolver.evaluateCondition('', context)).toBe(false);
    });
  });
  
  describe('evaluateExpression', () => {
    it('should evaluate simple expressions', async () => {
      const context = { price: 100, quantity: 3 };
      
      // For now, just variable substitution
      const result = await resolver.evaluateExpression('Total: ${price} x ${quantity}', context);
      expect(result).toBe('Total: 100 x 3');
    });
    
    it('should handle nested variable paths in expressions', async () => {
      const context = {
        product: {
          name: 'Widget',
          price: { amount: 99.99, currency: 'USD' }
        }
      };
      
      const result = await resolver.evaluateExpression(
        '${product.name} costs ${product.price.amount} ${product.price.currency}',
        context
      );
      
      expect(result).toBe('Widget costs 99.99 USD');
    });
  });
});