/**
 * Test Unified Evidence Fusion System
 * 
 * This test demonstrates the new separation of concerns between aggregation
 * (OWA) and reconciliation (bilattice/Dempster-Shafer) logic, supporting
 * both qualitative and quantitative modes with the same lexicon.
 */

import { test, describe } from 'node:test';
import assert from 'node:assert';
import {
  QualitativeScale,
  UnifiedEvidenceFusion,
  EvidenceAggregation,
  EvidenceReconciliation,
  NumericBilatticeOrderings
} from '../../src/qualitative/index.js';

describe('Unified Evidence Fusion System', () => {
  
  test('should demonstrate aggregation vs reconciliation separation', () => {
    // Test data with conflicting evidence
    const collectedValues = [
      {
        value: 0.8,
        possibility: 0.9,
        path: ['evidence1'],
        source: { type: 'direct', confidence: 0.95 },
        metadata: { timestamp: Date.now(), reliability: 0.9 }
      },
      {
        value: 0.3,
        possibility: 0.4,
        path: ['evidence2'],
        source: { type: 'inferred', confidence: 0.6 },
        metadata: { timestamp: Date.now(), reliability: 0.7 }
      },
      {
        value: 0.7,
        possibility: 0.6,
        path: ['evidence3'],
        source: { type: 'derived', confidence: 0.8 },
        metadata: { timestamp: Date.now(), reliability: 0.8 }
      }
    ];

    // Test pure aggregation (no reconciliation)
    const aggregationResult = UnifiedEvidenceFusion.fuse(collectedValues, {
      mode: 'quantitative',
      aggregationMethod: 'majority',
      useReconciliation: false
    });

    assert.ok(aggregationResult.hasValue);
    assert.strictEqual(aggregationResult.fusionMethod, 'aggregation');
    assert.strictEqual(aggregationResult.reconciliationMethod, 'none');
    assert.ok(aggregationResult.epistemicAnalysis === null);

    // Test reconciliation-based fusion
    const reconciliationResult = UnifiedEvidenceFusion.fuse(collectedValues, {
      mode: 'quantitative',
      aggregationMethod: 'max',
      reconciliationMethod: 'dempster_shafer',
      epistemicMode: 'hybrid',
      useReconciliation: true
    });

    assert.ok(reconciliationResult.hasValue);
    assert.strictEqual(reconciliationResult.fusionMethod, 'reconciliation');
    assert.strictEqual(reconciliationResult.reconciliationMethod, 'dempster_shafer');
    assert.ok(reconciliationResult.epistemicAnalysis !== null);
  });

  test('should support both qualitative and quantitative modes with same lexicon', () => {
    const collectedValues = [
      {
        value: 0.75, // Valid fivePoint scale value
        possibility: 0.75,
        path: ['evidence1'],
        source: { type: 'direct' },
        metadata: { reliability: 0.9 }
      },
      {
        value: 0.5, // Valid fivePoint scale value
        possibility: 0.5,
        path: ['evidence2'],
        source: { type: 'inferred' },
        metadata: { reliability: 0.7 }
      }
    ];

    const scale = QualitativeScale.fivePoint();

    // Test quantitative mode
    const quantitativeResult = UnifiedEvidenceFusion.fuse(collectedValues, {
      mode: 'quantitative',
      aggregationMethod: 'average',
      useReconciliation: false
    });

    // Test qualitative mode
    const qualitativeResult = UnifiedEvidenceFusion.fuse(collectedValues, {
      mode: 'qualitative',
      aggregationMethod: 'average',
      scale: scale,
      useReconciliation: false
    });

    assert.ok(quantitativeResult.hasValue);
    assert.ok(qualitativeResult.hasValue);
    assert.strictEqual(quantitativeResult.aggregationMethod, 'average');
    assert.strictEqual(qualitativeResult.aggregationMethod, 'average');
    
    // Both should use the same aggregation lexicon
    assert.ok(quantitativeResult.value > 0);
    assert.ok(qualitativeResult.value > 0);
  });

  test('should demonstrate numeric bilattice orderings', () => {
    // Create a simple numeric capacity
    const capacity = {
      stateSpace: ['evidence1', 'evidence2', 'evidence3'],
      getCapacity: (set) => {
        // For single elements
        if (set.size === 1) {
          if (set.has('evidence1')) return 0.8;
          if (set.has('evidence2')) return 0.6;
          if (set.has('evidence3')) return 0.4;
        }
        // For complements (multiple elements)
        if (set.size === 2) {
          return 0.2; // Some belief in complements
        }
        // For empty set
        if (set.size === 0) {
          return 0;
        }
        // For full set
        if (set.size === 3) {
          return 1.0;
        }
        return 0;
      }
    };

    const propositions = [['evidence1'], ['evidence2'], ['evidence3']];

    // Test information ordering
    const mostInformative = NumericBilatticeOrderings.findMostInformative(propositions, capacity);
    assert.ok(mostInformative);
    assert.strictEqual(mostInformative.rank, 1);

    // Test truth ordering
    const mostTrue = NumericBilatticeOrderings.findMostTrue(propositions, capacity);
    assert.ok(mostTrue);
    assert.strictEqual(mostTrue.rank, 1);

    // Test Dempster-Shafer measures
    const belief = NumericBilatticeOrderings.dempsterShaferBelief(['evidence1'], capacity);
    const plausibility = NumericBilatticeOrderings.dempsterShaferPlausibility(['evidence1'], capacity);
    const uncertainty = NumericBilatticeOrderings.dempsterShaferUncertainty(['evidence1'], capacity);

    assert.strictEqual(belief, 0.8);
    // Plausibility should be 1 - capacity of complement
    // Complement of ['evidence1'] is ['evidence2', 'evidence3']
    // Capacity of ['evidence2', 'evidence3'] is 0.2
    // So plausibility = 1 - 0.2 = 0.8
    assert.strictEqual(plausibility, 0.8);
    assert.strictEqual(uncertainty, 0); // 0.8 - 0.8 = 0
  });

  test('should demonstrate reconciliation methods comparison', () => {
    const collectedValues = [
      {
        value: 0.8,
        possibility: 0.9,
        path: ['evidence1'],
        source: { type: 'direct' },
        metadata: { reliability: 0.9 }
      },
      {
        value: 0.3,
        possibility: 0.4,
        path: ['evidence2'],
        source: { type: 'inferred' },
        metadata: { reliability: 0.7 }
      }
    ];

    // Test different reconciliation methods
    const bilatticeResult = UnifiedEvidenceFusion.fuse(collectedValues, {
      mode: 'quantitative',
      reconciliationMethod: 'bilattice',
      epistemicMode: 'hybrid',
      useReconciliation: true
    });

    const dempsterShaferResult = UnifiedEvidenceFusion.fuse(collectedValues, {
      mode: 'quantitative',
      reconciliationMethod: 'dempster_shafer',
      epistemicMode: 'hybrid',
      useReconciliation: true
    });

    const subjectiveLogicResult = UnifiedEvidenceFusion.fuse(collectedValues, {
      mode: 'quantitative',
      reconciliationMethod: 'subjective_logic',
      epistemicMode: 'hybrid',
      useReconciliation: true
    });

    // All should produce valid results
    assert.ok(bilatticeResult.hasValue);
    assert.ok(dempsterShaferResult.hasValue);
    assert.ok(subjectiveLogicResult.hasValue);

    // All should have epistemic analysis
    assert.ok(bilatticeResult.epistemicAnalysis);
    assert.ok(dempsterShaferResult.epistemicAnalysis);
    assert.ok(subjectiveLogicResult.epistemicAnalysis);

    // Different methods may produce different results
    console.log('Bilattice result:', bilatticeResult.value);
    console.log('Dempster-Shafer result:', dempsterShaferResult.value);
    console.log('Subjective Logic result:', subjectiveLogicResult.value);
  });

  test('should demonstrate aggregation methods comparison', () => {
    const collectedValues = [
      {
        value: 0.8,
        possibility: 0.8,
        path: ['evidence1'],
        source: { type: 'direct' },
        metadata: { reliability: 0.9 }
      },
      {
        value: 0.6,
        possibility: 0.6,
        path: ['evidence2'],
        source: { type: 'inferred' },
        metadata: { reliability: 0.7 }
      },
      {
        value: 0.4,
        possibility: 0.4,
        path: ['evidence3'],
        source: { type: 'derived' },
        metadata: { reliability: 0.8 }
      }
    ];

    const aggregationMethods = ['max', 'min', 'average', 'majority', 'median'];

    const results = {};
    for (const method of aggregationMethods) {
      results[method] = UnifiedEvidenceFusion.fuse(collectedValues, {
        mode: 'quantitative',
        aggregationMethod: method,
        useReconciliation: false
      });
    }

    // All methods should produce valid results
    for (const [method, result] of Object.entries(results)) {
      assert.ok(result.hasValue, `Method ${method} should produce valid result`);
      assert.strictEqual(result.aggregationMethod, method);
      assert.ok(result.value >= 0 && result.value <= 1);
    }

    // Different methods should produce different results
    assert.ok(results.max.value >= results.average.value);
    assert.ok(results.average.value >= results.min.value);
  });

  test('should demonstrate method comparison functionality', () => {
    const collectedValues = [
      {
        value: 0.7,
        possibility: 0.7,
        path: ['evidence1'],
        source: { type: 'direct' },
        metadata: { reliability: 0.9 }
      },
      {
        value: 0.5,
        possibility: 0.5,
        path: ['evidence2'],
        source: { type: 'inferred' },
        metadata: { reliability: 0.7 }
      }
    ];

    const comparison = UnifiedEvidenceFusion.compareMethods(collectedValues, {
      mode: 'quantitative',
      aggregationMethods: ['max', 'average', 'majority'],
      reconciliationMethods: ['none', 'dempster_shafer'],
      epistemicModes: ['hybrid']
    });

    assert.ok(comparison.results);
    assert.ok(comparison.summary);
    assert.ok(comparison.summary.bestMethods.length > 0);
    assert.ok(comparison.summary.worstMethods.length > 0);
    assert.ok(comparison.summary.valueRange.min <= comparison.summary.valueRange.max);
  });

  test('should validate fusion options', () => {
    const validation = UnifiedEvidenceFusion.validateOptions({
      mode: 'quantitative',
      aggregationMethod: 'max',
      reconciliationMethod: 'bilattice',
      epistemicMode: 'hybrid',
      capacityType: 'simple_support'
    });

    assert.ok(validation.valid);
    assert.strictEqual(validation.errors.length, 0);

    // Test invalid options
    const invalidValidation = UnifiedEvidenceFusion.validateOptions({
      mode: 'invalid',
      aggregationMethod: 'invalid',
      reconciliationMethod: 'invalid'
    });

    assert.ok(!invalidValidation.valid);
    assert.ok(invalidValidation.errors.length > 0);
  });

  test('should get available methods and descriptions', () => {
    const availableMethods = UnifiedEvidenceFusion.getAvailableMethods();
    assert.ok(availableMethods.aggregation);
    assert.ok(availableMethods.reconciliation);
    assert.ok(availableMethods.epistemicModes);
    assert.ok(availableMethods.capacityTypes);

    const descriptions = UnifiedEvidenceFusion.getMethodDescriptions();
    assert.ok(descriptions.aggregation);
    assert.ok(descriptions.reconciliation);
    assert.ok(descriptions.epistemicModes);
    assert.ok(descriptions.capacityTypes);

    // Test specific descriptions
    assert.ok(descriptions.aggregation.max);
    assert.ok(descriptions.reconciliation.bilattice);
    assert.ok(descriptions.epistemicModes.hybrid);
  });
});
