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

/**
 * AST node for fusion statements
 * Represents: fusion max { ... }
 */
export class FusionNode extends BaseNode {
  constructor(strategy, location = null) {
    super('Fusion', location);
    this.strategy = strategy; // 'max', 'min', 'majority', 'average', etc.
    this.evidence = []; // Array of evidence statements
    this.weights = null; // Optional weights array
  }

  /**
   * Add evidence to this fusion
   * @param {BaseNode} evidence - Evidence to add
   */
  addEvidence(evidence) {
    this.evidence.push(evidence);
    this.addChild(evidence);
  }

  /**
   * Set weights for this fusion
   * @param {number[]} weights - Weights array
   */
  setWeights(weights) {
    this.weights = weights;
  }

  /**
   * Get the fusion strategy
   * @returns {string} Fusion strategy
   */
  getStrategy() {
    return this.strategy;
  }

  /**
   * Get all evidence statements
   * @returns {BaseNode[]} Evidence statements
   */
  getEvidence() {
    return this.evidence;
  }

  /**
   * Get the weights for this fusion
   * @returns {number[]|null} Weights or null
   */
  getWeights() {
    return this.weights;
  }

  /**
   * Check if this fusion has weights
   * @returns {boolean} True if has weights
   */
  hasWeights() {
    return this.weights !== null && this.weights.length > 0;
  }

  /**
   * Check if this is a max fusion
   * @returns {boolean} True if max fusion
   */
  isMax() {
    return this.strategy === 'max';
  }

  /**
   * Check if this is a min fusion
   * @returns {boolean} True if min fusion
   */
  isMin() {
    return this.strategy === 'min';
  }

  /**
   * Check if this is a majority fusion
   * @returns {boolean} True if majority fusion
   */
  isMajority() {
    return this.strategy === 'majority';
  }

  /**
   * Check if this is an average fusion
   * @returns {boolean} True if average fusion
   */
  isAverage() {
    return this.strategy === 'average';
  }

  /**
   * Get the number of evidence statements
   * @returns {number} Number of evidence statements
   */
  getEvidenceCount() {
    return this.evidence.length;
  }

  /**
   * Validate the fusion
   * @returns {string[]} Array of error messages
   */
  validate() {
    const errors = [];

    // Validate strategy
    const validStrategies = [
      'max',
      'min',
      'majority',
      'average',
      'sum',
      'sum_unbounded',
      'median',
      'optimistic',
      'pessimistic',
      'top2',
      'top3',
      'priority',
      'custom',
      'count'
    ];
    if (!validStrategies.includes(this.strategy)) {
      errors.push(`Invalid fusion strategy: ${this.strategy}`);
    }

    // Validate evidence
    if (this.evidence.length === 0) {
      errors.push('Fusion must have at least one evidence statement');
    }

    // Validate each evidence statement
    this.evidence.forEach((ev, index) => {
      const evErrors = ev.validate ? ev.validate() : [];
      errors.push(...evErrors.map(err => `Evidence ${index + 1}: ${err}`));
    });

    // Validate weights
    if (this.weights !== null) {
      if (!Array.isArray(this.weights)) {
        errors.push('Weights must be an array');
      } else if (this.weights.length !== this.evidence.length) {
        errors.push('Weights array length must match evidence count');
      } else if (this.weights.some(w => typeof w !== 'number' || w < 0)) {
        errors.push('All weights must be non-negative numbers');
      } else if (this.strategy === 'custom') {
        const total = this.weights.reduce((sum, w) => sum + w, 0);
        if (Math.abs(total - 1.0) > 1e-6) {
          errors.push('Custom weights must sum to 1.0');
        }
      }
    }

    if (this.strategy === 'custom' && (!this.weights || this.weights.length === 0)) {
      errors.push('Custom fusion requires weights');
    }

    return errors;
  }

  toString() {
    const weightsStr = this.hasWeights() ? ` weights[${this.weights.length}]` : '';
    return `Fusion(${this.strategy}, ${this.evidence.length} evidence${weightsStr})`;
  }
}
