/**
 * Numeric Bilattice Orderings for Quantitative Evidence Fusion
 * 
 * This module provides bilattice orderings for numeric (quantitative) evidence,
 * complementing the qualitative bilattice orderings. It supports both traditional
 * bilattice theory and Dempster-Shafer/Subjective Logic approaches for handling
 * epistemic uncertainty in quantitative domains.
 * 
 * Key Concepts:
 * - Information Ordering: (c₁, c₁') ≥ᵢ (c₂, c₂') ⟺ c₁ ≥ c₂ and c₁' ≥ c₂'
 * - Truth Ordering: A ≥ₜ B ⟺ γ(A) ≥ γ(B) and γ(Bᶜ) ≥ γ(Aᶜ)
 * - Dempster-Shafer: Belief, Plausibility, and Uncertainty measures
 * - Subjective Logic: Opinion space with belief, disbelief, and uncertainty
 */

export class NumericBilatticeOrderings {
  /**
   * Information ordering for numeric epistemic pairs
   * Compares the information content of two epistemic states.
   * (c₁, c₁') ≥ᵢ (c₂, c₂') ⟺ c₁ ≥ c₂ and c₁' ≥ c₂'
   * 
   * @param {Object} epistemic1 - First epistemic pair {belief: number, disbelief: number}
   * @param {Object} epistemic2 - Second epistemic pair {belief: number, disbelief: number}
   * @returns {boolean} True if epistemic1 ≥ᵢ epistemic2
   */
  static informationOrdering(epistemic1, epistemic2) {
    const { belief: c1, disbelief: c1Prime } = epistemic1;
    const { belief: c2, disbelief: c2Prime } = epistemic2;
    
    // (c₁, c₁') ≥ᵢ (c₂, c₂') ⟺ c₁ ≥ c₂ and c₁' ≥ c₂'
    const beliefComparison = c1 >= c2;
    const disbeliefComparison = c1Prime >= c2Prime;
    
    return beliefComparison && disbeliefComparison;
  }
  
  /**
   * Truth ordering for numeric propositions
   * Compares the truth content of two propositions with respect to a capacity.
   * A ≥ₜ B ⟺ γ(A) ≥ γ(B) and γ(Bᶜ) ≥ γ(Aᶜ)
   * 
   * @param {Array|Set} propositionA - First proposition (subset of state space)
   * @param {Array|Set} propositionB - Second proposition (subset of state space)
   * @param {Object} capacity - Capacity function with getCapacity method
   * @returns {boolean} True if propositionA ≥ₜ propositionB
   */
  static truthOrdering(propositionA, propositionB, capacity) {
    const setA = propositionA instanceof Set ? propositionA : new Set(propositionA);
    const setB = propositionB instanceof Set ? propositionB : new Set(propositionB);
    
    const gammaA = capacity.getCapacity(setA);
    const gammaB = capacity.getCapacity(setB);
    
    // Get complements
    const stateSpace = new Set(capacity.stateSpace);
    const complementA = new Set([...stateSpace].filter(x => !setA.has(x)));
    const complementB = new Set([...stateSpace].filter(x => !setB.has(x)));
    
    const gammaComplementA = capacity.getCapacity(complementA);
    const gammaComplementB = capacity.getCapacity(complementB);
    
    // A ≥ₜ B ⟺ γ(A) ≥ γ(B) and γ(Bᶜ) ≥ γ(Aᶜ)
    const capacityComparison = gammaA >= gammaB;
    const complementComparison = gammaComplementB >= gammaComplementA;
    
    return capacityComparison && complementComparison;
  }
  
  /**
   * Compare epistemic status between two propositions
   * @param {Array|Set} propositionA - First proposition
   * @param {Array|Set} propositionB - Second proposition
   * @param {Object} capacity - Capacity function
   * @returns {Object} Comparison result with information and truth orderings
   */
  static compareEpistemicStatus(propositionA, propositionB, capacity) {
    const epistemicA = this._getEpistemicPair(propositionA, capacity);
    const epistemicB = this._getEpistemicPair(propositionB, capacity);
    
    return {
      informationOrdering: this.informationOrdering(epistemicA, epistemicB),
      truthOrdering: this.truthOrdering(propositionA, propositionB, capacity),
      epistemicA,
      epistemicB
    };
  }
  
  /**
   * Find the most informative proposition from a list
   * @param {Array} propositions - Array of propositions
   * @param {Object} capacity - Capacity function
   * @returns {Object} Most informative proposition with epistemic analysis
   */
  static findMostInformative(propositions, capacity) {
    if (propositions.length === 0) {
      return null;
    }
    
    // Convert all propositions to Sets and compute epistemic pairs
    const propositionData = propositions.map(prop => {
      const set = prop instanceof Set ? prop : new Set(prop);
      const epistemic = this._getEpistemicPair(set, capacity);
      return { set, epistemic, original: prop };
    });
    
    // Find the most informative using information ordering
    let mostInformative = propositionData[0];
    
    for (let i = 1; i < propositionData.length; i++) {
      const current = propositionData[i];
      
      // Check if current is more informative than current best
      if (this.informationOrdering(current.epistemic, mostInformative.epistemic)) {
        mostInformative = current;
      }
    }
    
    // The most informative proposition has rank 1
    return {
      proposition: mostInformative.original,
      epistemic: mostInformative.epistemic,
      rank: 1
    };
  }
  
  /**
   * Find the most true proposition from a list
   * @param {Array} propositions - Array of propositions
   * @param {Object} capacity - Capacity function
   * @returns {Object} Most true proposition with epistemic analysis
   */
  static findMostTrue(propositions, capacity) {
    if (propositions.length === 0) {
      return null;
    }
    
    // Convert all propositions to Sets and compute epistemic pairs
    const propositionData = propositions.map(prop => {
      const set = prop instanceof Set ? prop : new Set(prop);
      const epistemic = this._getEpistemicPair(set, capacity);
      return { set, epistemic, original: prop };
    });
    
    // Find the most true using truth ordering
    let mostTrue = propositionData[0];
    
    for (let i = 1; i < propositionData.length; i++) {
      const current = propositionData[i];
      
      // Check if current is more true than current best
      if (this.truthOrdering(current.original, mostTrue.original, capacity)) {
        mostTrue = current;
      }
    }
    
    // The most true proposition has rank 1
    return {
      proposition: mostTrue.original,
      epistemic: mostTrue.epistemic,
      rank: 1
    };
  }
  
  /**
   * Rank propositions by information content
   * @param {Array} propositions - Array of propositions
   * @param {Object} capacity - Capacity function
   * @returns {Array} Ranked propositions with epistemic analysis
   */
  static rankByInformation(propositions, capacity) {
    if (propositions.length === 0) {
      return [];
    }
    
    // Convert all propositions to Sets and compute epistemic pairs
    const propositionData = propositions.map(prop => {
      const set = prop instanceof Set ? prop : new Set(prop);
      const epistemic = this._getEpistemicPair(set, capacity);
      return { set, epistemic, original: prop };
    });
    
    // Sort by information ordering (most informative first)
    propositionData.sort((a, b) => {
      if (this.informationOrdering(a.epistemic, b.epistemic)) return -1;
      if (this.informationOrdering(b.epistemic, a.epistemic)) return 1;
      return 0;
    });
    
    // Assign ranks
    return propositionData.map((item, index) => ({
      proposition: item.original,
      epistemic: item.epistemic,
      rank: index + 1
    }));
  }
  
  /**
   * Rank propositions by truth content
   * @param {Array} propositions - Array of propositions
   * @param {Object} capacity - Capacity function
   * @returns {Array} Ranked propositions with epistemic analysis
   */
  static rankByTruth(propositions, capacity) {
    if (propositions.length === 0) {
      return [];
    }
    
    // Convert all propositions to Sets and compute epistemic pairs
    const propositionData = propositions.map(prop => {
      const set = prop instanceof Set ? prop : new Set(prop);
      const epistemic = this._getEpistemicPair(set, capacity);
      return { set, epistemic, original: prop };
    });
    
    // Sort by truth ordering (most true first)
    propositionData.sort((a, b) => {
      if (this.truthOrdering(a.original, b.original, capacity)) return -1;
      if (this.truthOrdering(b.original, a.original, capacity)) return 1;
      return 0;
    });
    
    // Assign ranks
    return propositionData.map((item, index) => ({
      proposition: item.original,
      epistemic: item.epistemic,
      rank: index + 1
    }));
  }
  
  /**
   * Dempster-Shafer belief function
   * @param {Array|Set} proposition - Proposition to evaluate
   * @param {Object} capacity - Capacity function
   * @returns {number} Belief value
   */
  static dempsterShaferBelief(proposition, capacity) {
    const set = proposition instanceof Set ? proposition : new Set(proposition);
    return capacity.getCapacity(set);
  }
  
  /**
   * Dempster-Shafer plausibility function
   * @param {Array|Set} proposition - Proposition to evaluate
   * @param {Object} capacity - Capacity function
   * @returns {number} Plausibility value
   */
  static dempsterShaferPlausibility(proposition, capacity) {
    const set = proposition instanceof Set ? proposition : new Set(proposition);
    const stateSpace = new Set(capacity.stateSpace);
    const complement = new Set([...stateSpace].filter(x => !set.has(x)));
    
    // Pl(A) = 1 - Bel(Aᶜ)
    // But we need to handle the case where the complement might be empty
    if (complement.size === 0) {
      return 1.0; // If complement is empty, plausibility is 1
    }
    
    return 1 - capacity.getCapacity(complement);
  }
  
  /**
   * Dempster-Shafer uncertainty function
   * @param {Array|Set} proposition - Proposition to evaluate
   * @param {Object} capacity - Capacity function
   * @returns {number} Uncertainty value
   */
  static dempsterShaferUncertainty(proposition, capacity) {
    const belief = this.dempsterShaferBelief(proposition, capacity);
    const plausibility = this.dempsterShaferPlausibility(proposition, capacity);
    
    // U(A) = Pl(A) - Bel(A)
    return plausibility - belief;
  }
  
  /**
   * Subjective Logic opinion from epistemic pair
   * @param {Object} epistemic - Epistemic pair {belief: number, disbelief: number}
   * @returns {Object} Subjective Logic opinion {b: belief, d: disbelief, u: uncertainty}
   */
  static subjectiveLogicOpinion(epistemic) {
    const { belief, disbelief } = epistemic;
    const uncertainty = Math.max(0, 1 - belief - disbelief);
    
    return {
      b: belief,        // Belief
      d: disbelief,     // Disbelief
      u: uncertainty    // Uncertainty
    };
  }
  
  /**
   * Subjective Logic expectation value
   * @param {Object} opinion - Subjective Logic opinion
   * @returns {number} Expectation value
   */
  static subjectiveLogicExpectation(opinion) {
    const { b, u } = opinion;
    // E = b + u/2 (assuming uniform distribution of uncertainty)
    return b + u / 2;
  }
  
  /**
   * Get epistemic pair for a proposition
   * @private
   */
  static _getEpistemicPair(proposition, capacity) {
    const stateSpace = new Set(capacity.stateSpace);
    const set = proposition instanceof Set ? proposition : new Set(proposition);
    
    const belief = capacity.getCapacity(set);
    const complement = new Set([...stateSpace].filter(x => !set.has(x)));
    const disbelief = capacity.getCapacity(complement);
    
    return { belief, disbelief };
  }
}
