/**
 * Simple Test Suite for Qualitative Capacity System
 * 
 * Tests core functionality using Node.js built-in test framework
 */

import { test, describe } from 'node:test';
import assert from 'node:assert/strict';
import { 
  QualitativeScale, 
  QualitativeCapacity, 
  QualitativeFusion, 
  OWAQualitativeFusion,
  getOWAQualitativeWeights,
  DEFAULT_QUALITATIVE_SCALE 
} from '../../src/qualitative/index.js';

describe('QualitativeScale', () => {
  test('should create scale with correct properties', () => {
    const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test');
    assert.deepStrictEqual(scale.values, [0, 0.25, 0.5, 0.75, 1]);
    assert.strictEqual(scale.bottom, 0);
    assert.strictEqual(scale.top, 1);
    assert.strictEqual(scale.size, 5);
  });
  
  test('should create correct negation map', () => {
    const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test');
    assert.strictEqual(scale.negate(0), 1);
    assert.strictEqual(scale.negate(1), 0);
    assert.strictEqual(scale.negate(0.25), 0.75);
    assert.strictEqual(scale.negate(0.5), 0.5);
    assert.strictEqual(scale.negate(0.75), 0.25);
  });
  
  test('should perform min/max operations correctly', () => {
    const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test');
    assert.strictEqual(scale.min(0.25, 0.75), 0.25);
    assert.strictEqual(scale.max(0.25, 0.75), 0.75);
    assert.strictEqual(scale.minAll([0.25, 0.5, 0.75]), 0.25);
    assert.strictEqual(scale.maxAll([0.25, 0.5, 0.75]), 0.75);
  });
  
  test('should compare values correctly', () => {
    const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test');
    assert.strictEqual(scale.compare(0.25, 0.75), -1);
    assert.strictEqual(scale.compare(0.75, 0.25), 1);
    assert.strictEqual(scale.compare(0.5, 0.5), 0);
  });
  
  test('should validate values are in scale', () => {
    const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test');
    assert.strictEqual(scale.contains(0.5), true);
    assert.strictEqual(scale.contains(0.3), false);
  });
  
  test('should create common scales correctly', () => {
    const binary = QualitativeScale.binary();
    assert.deepStrictEqual(binary.values, [0, 1]);
    
    const ternary = QualitativeScale.ternary();
    assert.deepStrictEqual(ternary.values, [0, 0.5, 1]);
    
    const fivePoint = QualitativeScale.fivePoint();
    assert.deepStrictEqual(fivePoint.values, [0, 0.25, 0.5, 0.75, 1]);
  });
});

describe('QualitativeCapacity', () => {
  test('should create capacity with correct properties', () => {
    const stateSpace = ['s1', 's2', 's3'];
    const scale = new QualitativeScale([0, 0.5, 1], 'test');
    
    // Create a QMT with some focal sets
    const qmt = new Map();
    qmt.set(new Set(['s1']), 0.5);
    qmt.set(new Set(['s1', 's2']), 1);
    qmt.set(new Set(['s1', 's2', 's3']), 1);
    
    const capacity = new QualitativeCapacity(stateSpace, scale, qmt);
    
    assert.deepStrictEqual(capacity.stateSpace, ['s1', 's2', 's3']);
    assert.strictEqual(capacity.scale, scale);
    assert.strictEqual(capacity.getFocalSets().length, 3);
  });
  
  test('should compute capacity values correctly', () => {
    const stateSpace = ['s1', 's2', 's3'];
    const scale = new QualitativeScale([0, 0.5, 1], 'test');
    
    const qmt = new Map();
    qmt.set(new Set(['s1']), 0.5);
    qmt.set(new Set(['s1', 's2']), 1);
    qmt.set(new Set(['s1', 's2', 's3']), 1);
    
    const capacity = new QualitativeCapacity(stateSpace, scale, qmt);
    
    assert.strictEqual(capacity.getCapacity(['s1']), 0.5);
    assert.strictEqual(capacity.getCapacity(['s1', 's2']), 1);
    assert.strictEqual(capacity.getCapacity(['s2']), 0); // Not a focal set
    assert.strictEqual(capacity.getCapacity(['s1', 's2', 's3']), 1);
  });
  
  test('should identify special capacity types', () => {
    const stateSpace = ['s1', 's2'];
    const scale = QualitativeScale.binary();
    
    // Test possibility measure (all focal sets are singletons)
    const possibilityQMT = new Map();
    possibilityQMT.set(new Set(['s1']), 1);
    possibilityQMT.set(new Set(['s2']), 0.5);
    
    const possibilityCapacity = new QualitativeCapacity(stateSpace, scale, possibilityQMT);
    assert.strictEqual(possibilityCapacity.isPossibilityMeasure(), true);
    assert.strictEqual(possibilityCapacity.isNecessityMeasure(), false);
    
    // Test necessity measure (focal sets form a nested chain)
    const necessityQMT = new Map();
    necessityQMT.set(new Set(['s1']), 0.5);
    necessityQMT.set(new Set(['s1', 's2']), 1);
    
    const necessityCapacity = new QualitativeCapacity(stateSpace, scale, necessityQMT);
    assert.strictEqual(necessityCapacity.isPossibilityMeasure(), false);
    assert.strictEqual(necessityCapacity.isNecessityMeasure(), true);
  });
  
  test('should create simple support capacities', () => {
    const stateSpace = ['s1', 's2', 's3'];
    const scale = QualitativeScale.binary();
    
    const ssc = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale);
    
    assert.strictEqual(ssc.getCapacity(['s1']), 1);
    assert.strictEqual(ssc.getCapacity(['s1', 's2']), 1);
    assert.strictEqual(ssc.getCapacity(['s2']), 0);
    assert.strictEqual(ssc.isNecessityMeasure(), true);
  });
});

describe('QualitativeFusion', () => {
  test('should perform normalized conjunctive fusion', () => {
    const stateSpace = ['s1', 's2'];
    const scale = QualitativeScale.binary();
    
    const capacity1 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale);
    const capacity2 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s2'], 1, scale);
    
    const fused = QualitativeFusion.normalizedConjunctive([capacity1, capacity2]);
    
    assert.deepStrictEqual(fused.stateSpace, stateSpace);
    assert.strictEqual(fused.scale, scale);
    assert.strictEqual(fused.getCapacity(['s1', 's2']), 1); // Full set should have top value
  });
  
  test('should perform disjunctive fusion', () => {
    const stateSpace = ['s1', 's2'];
    const scale = QualitativeScale.binary();
    
    const capacity1 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale);
    const capacity2 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s2'], 1, scale);
    
    const result = QualitativeFusion.disjunctive(capacity1, capacity2);
    
    assert.deepStrictEqual(result.stateSpace, stateSpace);
    assert.strictEqual(result.scale, scale);
    assert.strictEqual(result.getCapacity(['s1', 's2']), 1); // min(1, 1)
  });
  
  test('should compute Sugeno integral', () => {
    const stateSpace = ['s1', 's2'];
    const scale = QualitativeScale.ternary();
    
    const capacity = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale);
    const decisionFunction = { 's1': 0.5, 's2': 1 };
    
    const sugenoValue = QualitativeFusion.sugenoIntegral(capacity, decisionFunction);
    
    // Should be a value in the scale
    assert.strictEqual(scale.contains(sugenoValue), true);
    assert.ok(sugenoValue >= 0);
    assert.ok(sugenoValue <= 1);
  });
});

describe('OWAQualitativeFusion', () => {
  test('should perform qualitative OWA fusion', () => {
    const values = [0, 0.5, 1]; // Use values that are in the ternary scale
    const weights = [0, 0.5, 1]; // Use weights that are in the ternary scale
    const scale = QualitativeScale.ternary();
    
    const result = OWAQualitativeFusion.fuseWithMeta(values, weights, weights, 'max', scale);
    
    // The result should be a valid value in the scale
    assert.ok(scale.contains(result.value));
    assert.ok(result.meta);
  });
  
  test('should generate OWA weights correctly', () => {
    const scale = QualitativeScale.ternary();
    const maxWeights = getOWAQualitativeWeights('max', 3, null, scale);
    const minWeights = getOWAQualitativeWeights('min', 3, null, scale);
    
    assert.strictEqual(maxWeights[0], 1); // Top weight on first position
    assert.strictEqual(maxWeights[1], 0); // Bottom weight on others
    assert.strictEqual(maxWeights[2], 0);
    
    assert.strictEqual(minWeights[0], 0); // Bottom weight on first positions
    assert.strictEqual(minWeights[1], 0);
    assert.strictEqual(minWeights[2], 1); // Top weight on last position
  });
});

describe('Integration Tests', () => {
  test('should work with default qualitative scale', () => {
    const stateSpace = ['s1', 's2'];
    const capacity = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, DEFAULT_QUALITATIVE_SCALE);
    
    assert.strictEqual(capacity.scale, DEFAULT_QUALITATIVE_SCALE);
    assert.strictEqual(capacity.getCapacity(['s1']), 1);
  });
  
  test('should perform end-to-end fusion workflow', () => {
    const stateSpace = ['s1', 's2'];
    const scale = QualitativeScale.binary();
    
    // Create two simple support capacities
    const capacity1 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale);
    const capacity2 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s2'], 1, scale);
    
    // Fuse them using normalized conjunctive rule
    const fused = QualitativeFusion.normalizedConjunctive([capacity1, capacity2]);
    
    // Verify the result
    assert.deepStrictEqual(fused.stateSpace, stateSpace);
    assert.strictEqual(fused.scale, scale);
    assert.strictEqual(fused.getCapacity(['s1', 's2']), 1); // Full set should have top value
  });
  
  test('should handle edge cases gracefully', () => {
    const stateSpace = ['s1'];
    const scale = QualitativeScale.binary();
    
    // Test with single state
    const capacity = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale);
    assert.strictEqual(capacity.getCapacity(['s1']), 1);
    
    // Test with empty subset
    assert.strictEqual(capacity.getCapacity([]), 0);
  });
});
