const suits = ["♥", "♦", "♣", "♠"];
const ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];

class Card {
  constructor(suit, rank) {
    this.suit = suit;
    this.rank = rank;
  }
  
  toString() {
    return `${this.rank}${this.suit}`;
  }
}

function determineWinners(playerHands, boardCards) {
  const allHands = playerHands.map((hand) => [...hand, ...boardCards]);
  const bestHands = allHands.map((hand) => getBestHand(hand));
  const maxRank = Math.max(...bestHands.map((hand) => hand.rank));

  return bestHands.reduce((winners, hand, index) => {
    if (hand.rank === maxRank) {
      winners.push({
        playerId: index,
        winningCombinationId: hand.combination.id,
        winningCards: hand.cards,
      });
    }
    return winners;
  }, []);
}

function getBestHand(cards) {
  const combinations = [
    RoyalFlush,
    StraightFlush,
    FourOfAKind,
    FullHouse,
    Flush,
    Straight,
    ThreeOfAKind,
    TwoPairs,
    Pair
  ];

  for (const Combination of combinations) {
    const result = Combination.test(cards);
    if (result != null) {
      return { rank: Combination.rank, combination: result.combination, cards: result.cards };
    }
  }
}

class Combination {
  constructor(name, id, rank) {
    this.name = name;
    this.id = id;
    this.rank = rank;
  }

  static test(cards) {}
}



class FullHouse extends Combination {
    constructor() {
        super("Full house", 6, 6);
    }

    static test(cards) {
        const trioCardsArr = ThreeOfAKind.test(cards)?.cards;
        const pairsArr = Pair.test(cards)?.cards;

        if (trioCardsArr && pairsArr) {
            let trioIndex1 = cards.indexOf(trioCardsArr[0]);
            let trioIndex2 = cards.indexOf(trioCardsArr[2]);

            let houseArray = [].concat(pairsArr, trioCardsArr);
            let remainders = [];

            for (let i = 0; i < cards.length; i++) {
                let test = true;
                for (let j = 0; j < houseArray.length; j++) {
                    if (houseArray[j] === cards[i]) {
                        houseArray.splice(j, 1);
                        test = false;
                    }
                }

                if (test === true) {
                    remainders.push(cards[i]);
                }
            }

            return {
                combination: this,
                cards: [].concat.apply([], [cards[trioIndex1], cards[trioIndex1 + 1], cards[trioIndex2], cards[trioIndex2 + 1], houseArray.slice(0, 1)]),
            };
        } else {
            return null;
        }
    }
}


/////////////////////
class Pair extends Combination {
  constructor() {
    super("Pair", 1, 1);
  }

  static test(cards) {
    const pairs = [];
    
    // Loop through all possible pairs of cards
    for (let i = 0; i < cards.length - 1; i++) {
      for (let j = i + 1; j < cards.length; j++) {
        // If two cards have the same rank, add them to pairs array
        if (cards[i].rank === cards[j].rank) {
          pairs.push([cards[i], cards[j]]);
        }
      }
    }

    if (pairs.length === 0) { // no pair found
      return null;
    }

    // Sort by rank so highest-ranked pair comes first
    pairs.sort((a, b) => b[0].rank - a[0].rank);

    const output = {
      combination: this,
      cards: [].concat(...pairs), // flatten pairs array into single card array
    };

    return output;
  }
}

class ThreeOfAKind extends Combination {
  constructor() {
    super("Three of a kind", 3, 3);
  }

  static test(cards) {
    let trios = [];

    // Sort the input cards by rank
    const sortedCards = [...cards].sort((a, b) => ranks.indexOf(a.rank) - ranks.indexOf(b.rank));

    for (let i = 0; i <= sortedCards.length - 3; i++) {
      if (sortedCards[i].rank === sortedCards[i + 1].rank && sortedCards[i].rank === sortedCards[i + 2].rank) {
        trios.push([sortedCards[i], sortedCards[i + 1], sortedCards[i + 2]]);
      }
    }

    let remainingCards = sortedCards.filter(card => !trios.some(trio => trio.includes(card)));

    remainingCards.sort((a, b) => ranks.indexOf(b.rank) - ranks.indexOf(a.rank)); // Sort remaining cards in descending order

    if (!trios.length || remainingCards.length < 2) { // Use !trios.length instead of trios.length < 1
      return null;
    } else {
      let output = {
        combination: this,
        cards: trios[0]//[...trios[0], ...remainingCards.slice(0, 2)],
      };
      return output;
    }
  }
}

/////////////////////

// Define a function that tests the FullHouse class
function testFullHouse() {
  // Test case 1
  const cards1 = [
    new Card("♥", "A"),
    new Card("♦", "A"),
    new Card("♣", "A"),
    new Card("♠", "K"),
    new Card("♠", "Q"),
    new Card("♠", "J"),
    new Card("♦", "J")
  ];
  const expectedOutput1 = {
    combination: { name: 'Full house', id: 6, rank: 6 },
    cards: [
      'A♥',
      'A♦',
      'A♣',
      'K♠',
      'Q♠',
      'J♠',
      'J♦'
    ]
  };
  
  // Test case 2
  const cards2 = [
    new Card("♥", "8"),
    new Card("♥", "9"),
    new Card("♥", "10"),
    new Card("♥", "Q"),
    new Card("♥", "K"),
    new Card("♠", "7"),
    new Card("♦", "J")
  ];
  const expectedOutput2 = null;
  
   // Test case 3
   const cards3 = [
     new Card('♥', 'A'),
     new Card('♥', 'K'),
     ...ranks.slice(0,3).map(rank => new Card('✿', rank)),
     ...ranks.slice(3,5).map(rank =>new Card('★', rank))
   ];
   const expectedOutput3 ={
     combination:{name:"Full house" ,id :6,rank:6},
     cards:['2✿','2★','3✿','3★',"A♥","K♥"]
   }
  
  // Test case 4
  const cards4 = [
    new Card('♦︎', 'J'),
    new Card('♥', 'K'),
    ...ranks.slice(0,3).map(rank => new Card('✿', rank)),
    ...ranks.slice(3,5).map(rank =>new Card('★', rank)),
    new Card("♠", "A"),
    new Card("♣", "A")
  ];
  const expectedOutput4 ={
     combination:{name:"Full house" ,id :6,rank:6},
     cards:['A♠','A♣','2✿','2★','3✿']
   }
  
  // Verify the output of the FullHouse test cases
  console.log(
      (FullHouse.test(cards1)) , (expectedOutput1)
      , (FullHouse.test(cards2)) , (expectedOutput2)
      , (FullHouse.test(cards3)) , (expectedOutput3)
      , (FullHouse.test(cards4)) , (expectedOutput4)
      
  );
}

// Run the FullHouse test
testFullHouse();// fix the code please fullhowse func only works wrong