import { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import { DSLCompiler } from '../../src/ast/DSLCompiler.js';

function createMockArbiter() {
  const relationConfigs = new Map();
  return {
    relationConfigs,
    setRelationConfig(relation, config) {
      relationConfigs.set(relation, config);
    }
  };
}

describe('Measure Definitions', () => {
  const arbiter = createMockArbiter();
  const compiler = new DSLCompiler(arbiter);

  test('Basic measures', () => {
    const testCases = [
      {
        input: `measure userRole(user: User) {
          user.role
        } PROVIDES string`,
        description: 'Simple measure with attribute access'
      },
      {
        input: `measure userBalance(user: User) {
          user.balance
        } PROVIDES number`,
        description: 'Measure accessing numeric attribute'
      },
      {
        input: `measure isUserActive(user: User) {
          user.isActive
        } PROVIDES boolean`,
        description: 'Measure accessing boolean attribute'
      },
      {
        input: `measure userPermissions(user: User) {
          user.permissions
        } PROVIDES Permission[]`,
        description: 'Measure accessing array attribute'
      },
      {
        input: `measure userScore(user: User) {
          user.score
        } PROVIDES number`,
        description: 'Measure with behavior-inherited attribute'
      }
    ];

    testCases.forEach(({ input, description }) => {
      const result = compiler.compile(input, `test-basic-measure-${Date.now()}`);
      assert.ok(result.success, `${description} should parse successfully`);
      assert.ok(result.program.measures.length > 0, 'Should have measures');
    });
  });

  test('Measure return types', () => {
    const testCases = [
      { type: 'string', description: 'String return type' },
      { type: 'number', description: 'Number return type' },
      { type: 'boolean', description: 'Boolean return type' },
      { type: 'timestamp', description: 'Timestamp return type' },
      { type: 'Permission[]', description: 'Array return type' },
      { type: 'User', description: 'Custom type return' },
      { type: 'Group[]', description: 'Custom array return type' }
    ];

    testCases.forEach(({ type, description }) => {
      const dsl = `measure test() { true } PROVIDES ${type}`;
      const result = compiler.compile(dsl, `test-measure-return-${Date.now()}`);
      assert.ok(result.success, `${description} should parse successfully`);
    });
  });

  test('Measure aggregation', () => {
    const testCases = [
      {
        input: `measure userPermissions(user: User) {
          aggregate {
            user.role.permissions
            user.group.permissions
          } USING majority
        } PROVIDES Permission[]`,
        description: 'Aggregation with majority strategy'
      },
      {
        input: `measure userClearance(user: User) {
          aggregate {
            user.clearance
            user.role.clearance
            user.group.clearance
          } USING max
        } PROVIDES string`,
        description: 'Aggregation with max strategy'
      },
      {
        input: `measure userScore(user: User) {
          aggregate {
            user.reputation
            user.activityScore
            user.verificationLevel
          } USING average
        } PROVIDES number`,
        description: 'Aggregation with average strategy'
      },
      {
        input: `measure userTrust(user: User) {
          aggregate {
            user.reputation
            user.activityScore
            user.verificationLevel
            user.socialProof
          } USING min
        } PROVIDES number`,
        description: 'Aggregation with min strategy'
      }
    ];

    testCases.forEach(({ input, description }) => {
      const result = compiler.compile(input, `test-measure-aggregation-${Date.now()}`);
      assert.ok(result.success, `${description} should parse successfully`);
    });
  });

  test('Measure fusion', () => {
    const testCases = [
      {
        input: `measure effectiveClearance(user: User) {
          fusion max {
            user.clearance
            user.role.clearance
            user.group.clearance
          }
        } PROVIDES string`,
        description: 'Fusion with max strategy'
      },
      {
        input: `measure userPermissions(user: User) {
          fusion min {
            user.role.permissions
            user.group.permissions
          }
        } PROVIDES Permission[]`,
        description: 'Fusion with min strategy'
      },
      {
        input: `measure userScore(user: User) {
          fusion majority {
            user.reputation
            user.activityScore
            user.verificationLevel
          }
        } PROVIDES number`,
        description: 'Fusion with majority strategy'
      },
      {
        input: `measure userTrust(user: User) {
          fusion average {
            user.reputation
            user.activityScore
            user.verificationLevel
            user.socialProof
          }
        } PROVIDES number`,
        description: 'Fusion with average strategy'
      }
    ];

    testCases.forEach(({ input, description }) => {
      const result = compiler.compile(input, `test-measure-fusion-${Date.now()}`);
      assert.ok(result.success, `${description} should parse successfully`);
    });
  });

  test('Complex measures', () => {
    const testCases = [
      {
        input: `measure userEffectivePermissions(user: User) {
          aggregate {
            user.role.permissions
            user.group.permissions
            user.directPermissions
          } USING majority
        } PROVIDES Permission[]`,
        description: 'Complex aggregation with multiple sources'
      },
      {
        input: `measure userTrustScore(user: User) {
          fusion average {
            user.reputation
            user.activityScore
            user.verificationLevel
            user.socialProof
            user.peerRatings
          }
        } PROVIDES number`,
        description: 'Complex fusion with multiple metrics'
      },
      {
        input: `measure userAccessLevel(user: User) {
          fusion max {
            user.clearance
            user.role.clearance
            user.group.clearance
            user.temporaryClearance
          }
        } PROVIDES string`,
        description: 'Complex clearance calculation'
      },
      {
        input: `measure userSimilarity(user1: User, user2: User) {
          similar(user1, user2) |similarity| {
            similarity
          } with similarity > 0.5
        } PROVIDES number`,
        description: 'Similarity measure with pattern matching'
      },
      {
        input: `measure userEffectiveRole(user: User) {
          fusion majority {
            user.role
            user.temporaryRole
            user.actingRole
          }
        } PROVIDES string`,
        description: 'Role determination with multiple sources'
      }
    ];

    testCases.forEach(({ input, description }) => {
      const result = compiler.compile(input, `test-complex-measure-${Date.now()}`);
      assert.ok(result.success, `${description} should parse successfully`);
    });
  });

  test('Measure error handling', () => {
    const testCases = [
      {
        input: `measure userRole(user: User) {
          user.role
        }`,
        description: 'Missing PROVIDES clause should fail',
        expectSuccess: false
      },
      {
        input: `measure userRole(user: User) {
          user.role
        } PROVIDES`,
        description: 'Incomplete PROVIDES clause should fail',
        expectSuccess: false
      },
      {
        input: `measure userRole(user: User) {
          user.role
        } PROVIDES string`,
        description: 'Valid measure should succeed',
        expectSuccess: true
      },
      {
        input: `measure userPermissions(user: User) {
          aggregate {
            user.role.permissions
            user.group.permissions
          } USING
        } PROVIDES Permission[]`,
        description: 'Incomplete USING clause should fail',
        expectSuccess: false
      },
      {
        input: `measure userScore(user: User) {
          fusion {
            user.reputation
            user.activityScore
          }
        } PROVIDES number`,
        description: 'Missing fusion strategy should fail',
        expectSuccess: false
      },
      {
        input: `measure userRole(user: User) {
          invalid syntax here
        } PROVIDES string`,
        description: 'Invalid syntax should fail',
        expectSuccess: false
      }
    ];

    testCases.forEach(({ input, description, expectSuccess }) => {
      try {
        const result = compiler.compile(input, `test-measure-error-${Date.now()}`);
        if (expectSuccess) {
          assert.ok(result.success, `${description} should parse successfully`);
        } else {
          assert.ok(!result.success, `${description} should fail to parse`);
        }
      } catch {
        if (!expectSuccess) {
          // Expected to fail
        }
      }
    });
  });
});
