#[allow(nonstandard_style)]
mod casino__table_split_pot_tests {
    use pkcore::prelude::*;

    fn preroll(index: &str) -> TableCelled {
        let table = TestData::split_pot_table(&cc!(index));

        assert_eq!(46, table.deck.len());

        table.act_forced_bets().expect("forced bets should post");

        assert!(table.seats.are_dealt());
        assert_eq!(3, table.seats.count_players_with_action_to_give());

        table.act_all_in(0).expect("seat 0 should be able to go all-in");
        table.act_all_in(1).expect("seat 1 should be able to go all-in");
        table.act_all_in(2).expect("seat 2 should be able to go all-in");

        assert_eq!(PlayerState::Bet(9_000), table.get_seat(0).unwrap().player.state.get());

        assert_eq!(1, table.seats.count_players_with_action_to_give());
        assert!(table.is_betting_complete());

        table.bring_it_in().expect("flop should be dealt");

        assert_eq!(PlayerState::Bet(9_000), table.get_seat(0).unwrap().player.state.get());

        table.deal_flop().expect("flop should be dealt");

        assert_eq!(PlayerState::Bet(9_000), table.get_seat(0).unwrap().player.state.get());
        assert_eq!(1, table.seats.count_players_with_action_to_give());
        assert!(!table.is_game_over());
        assert!(table.is_betting_complete());

        table.deal_turn().expect("turn should be dealt");
        assert_eq!(PlayerState::Bet(9_000), table.get_seat(0).unwrap().player.state.get());
        assert!(!table.is_game_over());
        assert!(table.is_betting_complete());

        table.deal_river().expect("river should be dealt");
        assert_eq!(PlayerState::Bet(9_000), table.get_seat(0).unwrap().player.state.get());
        assert!(table.is_betting_complete());
        assert!(table.is_game_over());

        table
    }

    /// Winning scenarios:
    ///
    /// -
    #[test]
    fn deals_to_river_after_preflop_all_ins__rich_man() {
        let table = preroll(
            "K♠ Q♠ Q♥ Q♣ J♠ A♦ T♠ 9♠ 8♠ 7♠ 6♠ 5♠ 4♠ 3♠ 2♠ K♥ J♥ T♥ 9♥ 8♥ 7♥ 6♥ 5♥ 4♥ 3♥ 2♥ K♦ J♦ T♦ 9♦ 8♦ 7♦ 6♦ 5♦ 3♦ 2♦ K♣ J♣ T♣ 9♣ 8♣ 7♣ 6♣ 5♣ 3♣ 2♣",
        );

        let winnings = table.end_hand().expect("hand should end successfully");
        assert!(
            !winnings.is_empty(),
            "winnings should not be empty after a completed hand"
        );
    }

    #[test]
    fn deals_to_river_after_preflop_all_ins__average() {
        let table = preroll(
            "4♠ Q♠ 8♠ 4♥ J♠ A♣ A♦ T♠ K♠ 9♠ 7♠ 6♠ 5♠ 3♠ 2♠ K♥ Q♥ J♥ T♥ 9♥ 8♥ 7♥ 6♥ 5♥ 3♥ 2♥ K♦ J♦ T♦ 9♦ 8♦ 7♦ 6♦ 5♦ 3♦ 2♦ K♣ J♣ T♣ 9♣ 8♣ 7♣ 6♣ 5♣ 3♣ 2♣",
        );

        let winnings = table.end_hand().expect("hand should end successfully");
        assert!(
            !winnings.is_empty(),
            "winnings should not be empty after a completed hand"
        );
    }

    #[test]
    fn deals_to_river_after_preflop_all_ins__poor_man_then_rich() {
        let table = preroll(
            "K♠ Q♠ A♦ J♠ A♣ T♠ 9♠ 8♠ 7♠ 6♠ 5♠ 4♠ 3♠ 2♠ K♥ Q♥ J♥ T♥ 9♥ 8♥ 7♥ 6♥ 5♥ 4♥ 3♥ 2♥ K♦ J♦ T♦ 9♦ 8♦ 7♦ 6♦ 5♦ 3♦ 2♦ K♣ J♣ T♣ 9♣ 8♣ 7♣ 6♣ 5♣ 3♣ 2♣",
        );

        // Verify chips in play for each seat before resolving the hand
        let s0_chips_in_play = table.get_seat(0).unwrap().player.get_chips_in_play();
        let s1_chips_in_play = table.get_seat(1).unwrap().player.get_chips_in_play();
        let s2_chips_in_play = table.get_seat(2).unwrap().player.get_chips_in_play();

        // Expectations derived from the simulated actions in `preroll`:
        // - Seat 0 (Rich Man) bet 9_000 into play
        // - Seat 1 (Poor Man) went all-in with 5_000
        // - Seat 2 (Average Person) went all-in with 9_000
        assert_eq!(s0_chips_in_play, 9_000, "Seat 0 chips_in_play");
        assert_eq!(s1_chips_in_play, 5_000, "Seat 1 chips_in_play");
        assert_eq!(s2_chips_in_play, 9_000, "Seat 2 chips_in_play");

        let winnings = table.end_hand().expect("hand should end successfully");

        assert!(!table.event_log.entries().is_empty(), "event log should have entries");
        // Two separate pot wins: Poor Man takes the main pot, Rich Man takes the side pot.
        assert!(winnings.len() >= 2, "split pot should produce at least two pot wins");
    }

    #[test]
    fn plus_blinds() {
        let table = TestData::preroll_split_pot_with_blinds__to_completion(
            "K♠ Q♠ A♦ J♠ A♣ T♠ 9♠ 8♠ 7♠ 6♠ 5♠ 4♠ K♥ Q♥ J♥ T♥ 9♥ 8♥ 7♥ 6♥ 5♥ 4♥ 3♥ 2♥ K♦ J♦ T♦ 9♦ 8♦ 7♦ 6♦ 5♦ 3♦ 2♦ K♣ J♣ T♣ 9♣ 6♣ 5♣ 3♣ 2♣",
        );

        // Two equal stacks (seats 0 and 4 at 9_000), one short stack (seat 3 at 5_000),
        // and two separate folded-blind NONE entries (50 and 100) — four equity groups.
        // NONE entries are intentionally kept separate so winnings() counts each
        // as an independent contributor rather than a single combined pool.
        let equity = table.determine_hand_equity();
        assert_eq!(4, equity.len(), "expected four equity groups");
        assert_eq!(9_000, equity.ceiling(), "ceiling should be the short-stack threshold");

        let winnings = table.end_hand().expect("hand should end successfully");
        assert!(
            !winnings.is_empty(),
            "winnings should not be empty after a completed hand"
        );
    }
}

#[allow(nonstandard_style)]
mod casino__table_no_cell__split_pot_tests {
    use pkcore::arrays::sliced::BoxedCards;
    use pkcore::casino::game::ForcedBets;
    use pkcore::casino::table_no_cell::{PlayerNoCell, SeatNoCell, SeatsNoCell, TableNoCell};
    use std::str::FromStr;

    /// Regression test: BB folds after posting 100 when all others go all-in for < 100.
    ///
    /// Trigger: BB's `chips_in_play` (100) exceeds every active (non-folded) player's
    /// `chips_in_play` (max = 80).  Before the fix, `showdown_multiway()` would break
    /// out of its side-pot loop with `eligible_seats.is_empty()`, leaving the orphaned
    /// `Seatbit::NONE` chips undistributed and causing `end_hand()` to return
    /// `Err(PKError::ChipAuditFailed)`.
    ///
    /// After the fix, orphaned NONE chips are drained to the most recent pot winner so
    /// chip conservation holds and `end_hand()` returns `Ok(winnings)`.
    #[test]
    fn bb_folds_over_contribution_no_chip_loss() {
        // Pre-set hole cards on seats so nlh_from_seats() removes them from the deck,
        // preventing duplicates in community cards.
        let mut seat0 = SeatNoCell::new(PlayerNoCell::new_with_chips("BTN".to_string(), 70));
        seat0.cards = BoxedCards::from_str("7♦ 2♣").unwrap();
        let mut seat1 = SeatNoCell::new(PlayerNoCell::new_with_chips("SB".to_string(), 80));
        seat1.cards = BoxedCards::from_str("8♦ 3♣").unwrap();
        let mut seat2 = SeatNoCell::new(PlayerNoCell::new_with_chips("BB".to_string(), 600));
        seat2.cards = BoxedCards::from_str("9♠ 4♦").unwrap();
        let mut seat3 = SeatNoCell::new(PlayerNoCell::new_with_chips("UTG".to_string(), 30));
        seat3.cards = BoxedCards::from_str("A♠ A♥").unwrap();

        let seats = SeatsNoCell::new(vec![seat0, seat1, seat2, seat3]);
        let mut table = TableNoCell::nlh_from_seats(seats, ForcedBets::new(50, 100));

        // SB posts 50, BB posts 100; hand_chip_total = 280.
        table.act_forced_bets().unwrap();

        // Pre-flop action: UTG → BTN → SB → BB
        let utg = table.next_to_act(); // seat 3: 30 chips_in_play
        table.act_all_in(utg).unwrap();
        let btn = table.next_to_act(); // seat 0: 70 chips_in_play
        table.act_all_in(btn).unwrap();
        let sb = table.next_to_act(); // seat 1: 80 chips_in_play
        table.act_all_in(sb).unwrap();
        let bb = table.next_to_act(); // seat 2: no full raise; BB folds
        table.act_fold(bb).unwrap(); // chips_in_play=100 > max_active=80 → orphaned NONE entry

        table.bring_it_in().unwrap();
        table.deal_flop().unwrap();
        table.deal_turn().unwrap();
        table.deal_river().unwrap();
        assert!(table.is_game_over());

        let result = table.end_hand();
        assert!(
            result.is_ok(),
            "end_hand should not fail with ChipAuditFailed when BB over-contributes and folds: {result:?}"
        );
    }
}
