/**
 * Measure Definition Tests
 * 
 * Tests the measure system of the Evidence DSL,
 * including aggregation, fusion, return types, and value computation.
 */

import { DSLCompiler } from '../DSLCompiler.js';

export class MeasureTests {
  constructor() {
    this.arbiter = null;
    this.compiler = null;
    this.testResults = [];
  }

  setup(arbiter) {
    this.arbiter = arbiter;
    this.compiler = new DSLCompiler(arbiter);
  }

  runAllTests() {
    console.log('=== Measure Definition Tests ===\n');

    this.testBasicMeasures();
    this.testMeasureReturnTypes();
    this.testMeasureAggregation();
    this.testMeasureFusion();
    this.testComplexMeasures();
    this.testMeasureErrors();

    return this.getTestResults();
  }

  testBasicMeasures() {
    console.log('Testing 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 }) => {
      try {
        const result = this.compiler.compile(input, `test-basic-measure-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        this.assert(result.program.measures.length > 0, 'Should have measures');
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Basic measure test: ${description}`, error);
      }
    });
  }

  testMeasureReturnTypes() {
    console.log('Testing 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 }) => {
      try {
        const dsl = `measure test() { true } PROVIDES ${type}`;
        const result = this.compiler.compile(dsl, `test-measure-return-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Measure return type test: ${description}`, error);
      }
    });
  }

  testMeasureAggregation() {
    console.log('Testing 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 }) => {
      try {
        const result = this.compiler.compile(input, `test-measure-aggregation-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Measure aggregation test: ${description}`, error);
      }
    });
  }

  testMeasureFusion() {
    console.log('Testing 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 }) => {
      try {
        const result = this.compiler.compile(input, `test-measure-fusion-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Measure fusion test: ${description}`, error);
      }
    });
  }

  testComplexMeasures() {
    console.log('Testing 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 }) => {
      try {
        const result = this.compiler.compile(input, `test-complex-measure-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Complex measure test: ${description}`, error);
      }
    });
  }

  testMeasureErrors() {
    console.log('Testing Measure Error Handling...');
    
    const testCases = [
      {
        input: `measure userRole(user: User) {
          user.role
        }`,
        description: 'Missing PROVIDES clause should fail'
      },
      {
        input: `measure userRole(user: User) {
          user.role
        } PROVIDES`,
        description: 'Incomplete PROVIDES clause should fail'
      },
      {
        input: `measure userRole(user: User) {
          user.role
        } PROVIDES string`,
        description: 'Valid measure should succeed'
      },
      {
        input: `measure userPermissions(user: User) {
          aggregate {
            user.role.permissions
            user.group.permissions
          } USING
        } PROVIDES Permission[]`,
        description: 'Incomplete USING clause should fail'
      },
      {
        input: `measure userScore(user: User) {
          fusion {
            user.reputation
            user.activityScore
          }
        } PROVIDES number`,
        description: 'Missing fusion strategy should fail'
      },
      {
        input: `measure userRole(user: User) {
          invalid syntax here
        } PROVIDES string`,
        description: 'Invalid syntax should fail'
      }
    ];

    testCases.forEach(({ input, description }) => {
      try {
        const result = this.compiler.compile(input, `test-measure-error-${Date.now()}`);
        if (description.includes('should succeed')) {
          this.assert(result.success, `${description} should parse successfully`);
          console.log(`  ✓ ${description}`);
        } else {
          this.assert(!result.success, `${description} should fail to parse`);
          console.log(`  ✓ ${description} (correctly failed)`);
        }
      } catch (error) {
        if (description.includes('should succeed')) {
          this.fail(`Measure error test: ${description}`, error);
        } else {
          // Expected to fail
          console.log(`  ✓ ${description} (correctly failed)`);
        }
      }
    });
  }

  assert(condition, message) {
    if (!condition) {
      throw new Error(`Assertion failed: ${message}`);
    }
  }

  fail(testName, error) {
    console.log(`  ✗ ${testName} failed: ${error.message}`);
    this.testResults.push({
      test: testName,
      status: 'FAILED',
      error: error.message
    });
  }

  getTestResults() {
    const passed = this.testResults.filter(r => r.status === 'PASSED').length;
    const failed = this.testResults.filter(r => r.status === 'FAILED').length;
    const total = this.testResults.length;

    return {
      total: total,
      passed: passed,
      failed: failed,
      success: failed === 0,
      results: this.testResults
    };
  }
}

export function runMeasureTests(arbiter) {
  const test = new MeasureTests();
  test.setup(arbiter);
  return test.runAllTests();
}
