/**
 * Bilattice Orderings for Evidential Reasoning
 * 
 * Implements the bilattice orderings (≥ᵢ, ≥ₜ) for comparing the epistemic status 
 * of propositions in qualitative capacity systems as described in the research paper.
 * 
 * These orderings are essential for evidential reasoning where we need to compare
 * the strength of evidence for different propositions.
 */

import { QualitativeCapacity } from './QualitativeCapacity.js';
import { QualitativeScale } from './QualitativeScale.js';
import { getSetKey } from './SetUtils.js';

export class BilatticeOrderings {
  
  /**
   * Information Ordering (≥ᵢ)
   * 
   * Compares the information content of two epistemic pairs.
   * (c₁, c₁') ≥ᵢ (c₂, c₂') ⟺ c₁ ≥ c₂ and c₁' ≥ c₂'
   * 
   * This ordering captures the idea that one epistemic state is more informative
   * than another if it provides higher confidence in both the proposition and its negation.
   * 
   * @param {Object} epistemic1 - First epistemic pair {belief: number, disbelief: number}
   * @param {Object} epistemic2 - Second epistemic pair {belief: number, disbelief: number}
   * @param {QualitativeScale} scale - The qualitative scale to use for comparison
   * @returns {boolean} True if epistemic1 ≥ᵢ epistemic2
   */
  static informationOrdering(epistemic1, epistemic2, scale) {
    const { belief: c1, disbelief: c1Prime } = epistemic1;
    const { belief: c2, disbelief: c2Prime } = epistemic2;
    
    // (c₁, c₁') ≥ᵢ (c₂, c₂') ⟺ c₁ ≥ c₂ and c₁' ≥ c₂'
    const beliefComparison = scale.compare(c1, c2) >= 0;
    const disbeliefComparison = scale.compare(c1Prime, c2Prime) >= 0;
    
    return beliefComparison && disbeliefComparison;
  }
  
  /**
   * Truth Ordering (≥ₜ)
   * 
   * Compares the truth content of two propositions with respect to a capacity.
   * A ≥ₜ B ⟺ γ(A) ≥ γ(B) and γ(Bᶜ) ≥ γ(Aᶜ)
   * 
   * This ordering captures the idea that proposition A is "more true" than B
   * if A has higher capacity value and its complement has lower capacity value.
   * 
   * @param {Set|Array} propositionA - First proposition (subset of state space)
   * @param {Set|Array} propositionB - Second proposition (subset of state space)
   * @param {QualitativeCapacity} capacity - The capacity function
   * @returns {boolean} True if A ≥ₜ B
   */
  static truthOrdering(propositionA, propositionB, capacity) {
    const scale = capacity.scale;
    const stateSpace = new Set(capacity.stateSpace);
    
    // Convert to Sets if needed
    const setA = propositionA instanceof Set ? propositionA : new Set(propositionA);
    const setB = propositionB instanceof Set ? propositionB : new Set(propositionB);
    
    // Get capacity values using canonical keys
    const gammaA = capacity.getCapacity(setA);
    const gammaB = capacity.getCapacity(setB);
    
    // Compute complements
    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 = scale.compare(gammaA, gammaB) >= 0;
    const complementComparison = scale.compare(gammaComplementB, gammaComplementA) >= 0;
    
    return capacityComparison && complementComparison;
  }
  
  /**
   * Compare epistemic status of two propositions
   * 
   * This is a comprehensive comparison that considers both information and truth orderings.
   * It returns a detailed comparison result indicating the relationship between the propositions.
   * 
   * @param {Set|Array} propositionA - First proposition
   * @param {Set|Array} propositionB - Second proposition
   * @param {QualitativeCapacity} capacity - The capacity function
   * @returns {Object} Comparison result with detailed analysis
   */
  static compareEpistemicStatus(propositionA, propositionB, capacity) {
    const scale = capacity.scale;
    const stateSpace = new Set(capacity.stateSpace);
    
    // Convert to Sets if needed
    const setA = propositionA instanceof Set ? propositionA : new Set(propositionA);
    const setB = propositionB instanceof Set ? propositionB : new Set(propositionB);
    
    // Get capacity values and complements
    const gammaA = capacity.getCapacity(setA);
    const gammaB = capacity.getCapacity(setB);
    
    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);
    
    // Create epistemic pairs
    const epistemicA = { belief: gammaA, disbelief: gammaComplementA };
    const epistemicB = { belief: gammaB, disbelief: gammaComplementB };
    
    // Apply orderings
    const informationOrdering = this.informationOrdering(epistemicA, epistemicB, scale);
    const truthOrdering = this.truthOrdering(setA, setB, capacity);
    
    // Determine relationship
    let relationship = 'incomparable';
    if (informationOrdering && truthOrdering) {
      relationship = 'A dominates B';
    } else if (this.informationOrdering(epistemicB, epistemicA, scale) && 
               this.truthOrdering(setB, setA, capacity)) {
      relationship = 'B dominates A';
    } else if (informationOrdering) {
      relationship = 'A more informative than B';
    } else if (truthOrdering) {
      relationship = 'A more true than B';
    } else if (this.informationOrdering(epistemicB, epistemicA, scale)) {
      relationship = 'B more informative than A';
    } else if (this.truthOrdering(setB, setA, capacity)) {
      relationship = 'B more true than A';
    }
    
    return {
      propositionA: {
        set: setA,
        capacity: gammaA,
        complement: gammaComplementA,
        epistemic: epistemicA
      },
      propositionB: {
        set: setB,
        capacity: gammaB,
        complement: gammaComplementB,
        epistemic: epistemicB
      },
      informationOrdering,
      truthOrdering,
      relationship,
      analysis: this._analyzeComparison(epistemicA, epistemicB, scale)
    };
  }
  
  /**
   * Find the most informative proposition from a set of propositions
   * 
   * @param {Array<Set|Array>} propositions - Array of propositions to compare
   * @param {QualitativeCapacity} capacity - The capacity function
   * @returns {Object} The most informative proposition and its analysis
   */
  static findMostInformative(propositions, capacity) {
    if (propositions.length === 0) {
      throw new Error('Cannot find most informative from empty set');
    }
    
    if (propositions.length === 1) {
      return {
        proposition: propositions[0],
        epistemic: this._getEpistemicPair(propositions[0], capacity),
        rank: 1,
        total: 1
      };
    }
    
    const scale = capacity.scale;
    const stateSpace = new Set(capacity.stateSpace);
    
    // 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, scale)) {
        mostInformative = current;
      }
    }
    
    // The most informative proposition has rank 1
    const rank = 1;
    
    return {
      proposition: mostInformative.original,
      epistemic: mostInformative.epistemic,
      rank,
      total: propositions.length,
      analysis: `Most informative proposition with belief=${mostInformative.epistemic.belief}, disbelief=${mostInformative.epistemic.disbelief}`
    };
  }
  
  /**
   * Find the most true proposition from a set of propositions
   * 
   * @param {Array<Set|Array>} propositions - Array of propositions to compare
   * @param {QualitativeCapacity} capacity - The capacity function
   * @returns {Object} The most true proposition and its analysis
   */
  static findMostTrue(propositions, capacity) {
    if (propositions.length === 0) {
      throw new Error('Cannot find most true from empty set');
    }
    
    if (propositions.length === 1) {
      return {
        proposition: propositions[0],
        capacity: capacity.getCapacity(propositions[0] instanceof Set ? propositions[0] : new Set(propositions[0])),
        rank: 1,
        total: 1
      };
    }
    
    const scale = capacity.scale;
    const stateSpace = new Set(capacity.stateSpace);
    
    // Convert all propositions to Sets and compute capacity values
    const propositionData = propositions.map(prop => {
      const set = prop instanceof Set ? prop : new Set(prop);
      const capacityValue = capacity.getCapacity(set);
      return { set, capacityValue, 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.set, mostTrue.set, capacity)) {
        mostTrue = current;
      }
    }
    
    // The most true proposition has rank 1
    const rank = 1;
    
    return {
      proposition: mostTrue.original,
      capacity: mostTrue.capacityValue,
      rank,
      total: propositions.length,
      analysis: `Most true proposition with capacity=${mostTrue.capacityValue}`
    };
  }
  
  /**
   * Rank propositions by information content
   * 
   * @param {Array<Set|Array>} propositions - Array of propositions to rank
   * @param {QualitativeCapacity} capacity - The capacity function
   * @returns {Array} Ranked propositions with epistemic analysis
   */
  static rankByInformation(propositions, capacity) {
    const scale = capacity.scale;
    
    // Convert to proposition data with 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 content (descending)
    propositionData.sort((a, b) => {
      const aMoreInformative = this.informationOrdering(a.epistemic, b.epistemic, scale);
      const bMoreInformative = this.informationOrdering(b.epistemic, a.epistemic, scale);
      
      if (aMoreInformative && !bMoreInformative) return -1;
      if (bMoreInformative && !aMoreInformative) return 1;
      return 0; // Incomparable or equal
    });
    
    return propositionData.map((data, index) => ({
      rank: index + 1,
      proposition: data.original,
      epistemic: data.epistemic,
      analysis: `Rank ${index + 1}: belief=${data.epistemic.belief}, disbelief=${data.epistemic.disbelief}`
    }));
  }
  
  /**
   * Rank propositions by truth content
   * 
   * @param {Array<Set|Array>} propositions - Array of propositions to rank
   * @param {QualitativeCapacity} capacity - The capacity function
   * @returns {Array} Ranked propositions with truth analysis
   */
  static rankByTruth(propositions, capacity) {
    const scale = capacity.scale;
    
    // Convert to proposition data with capacity values
    const propositionData = propositions.map(prop => {
      const set = prop instanceof Set ? prop : new Set(prop);
      const capacityValue = capacity.getCapacity(set);
      return { set, capacityValue, original: prop };
    });
    
    // Sort by truth content (descending)
    propositionData.sort((a, b) => {
      const aMoreTrue = this.truthOrdering(a.set, b.set, capacity);
      const bMoreTrue = this.truthOrdering(b.set, a.set, capacity);
      
      if (aMoreTrue && !bMoreTrue) return -1;
      if (bMoreTrue && !aMoreTrue) return 1;
      return 0; // Incomparable or equal
    });
    
    return propositionData.map((data, index) => ({
      rank: index + 1,
      proposition: data.original,
      capacity: data.capacityValue,
      analysis: `Rank ${index + 1}: capacity=${data.capacityValue}`
    }));
  }
  
  /**
   * 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 };
  }
  
  /**
   * Analyze comparison between two epistemic pairs
   * @private
   */
  static _analyzeComparison(epistemicA, epistemicB, scale) {
    const { belief: c1, disbelief: c1Prime } = epistemicA;
    const { belief: c2, disbelief: c2Prime } = epistemicB;
    
    const beliefDiff = scale.compare(c1, c2);
    const disbeliefDiff = scale.compare(c1Prime, c2Prime);
    
    let analysis = [];
    
    if (beliefDiff > 0) {
      analysis.push('A has higher belief than B');
    } else if (beliefDiff < 0) {
      analysis.push('B has higher belief than A');
    } else {
      analysis.push('A and B have equal belief');
    }
    
    if (disbeliefDiff > 0) {
      analysis.push('A has higher disbelief than B');
    } else if (disbeliefDiff < 0) {
      analysis.push('B has higher disbelief than A');
    } else {
      analysis.push('A and B have equal disbelief');
    }
    
    return analysis.join('; ');
  }
}
