use super::{deal::*, deck::*};
use const_fn_assert::cfn_assert;

const fn count_combination(m: u64, n: u64) -> u64 {
    cfn_assert!(n <= m);
    let mut comb = 1 as u64;
    let start_i = [m, n][(m < n) as usize]; //这是一个max函数的写法
    let mut i = start_i;

    while i < m {
        i += 1;
        comb *= i;
        comb /= i - start_i;
    }
    comb
}

pub const fn deal_hand_combination_street<const N: usize>(
    deck_size: usize,
    deal_hole_street: &'static [u8],
    deal_board_street: &'static [u8],
) -> [i32; N] {
    let mut arr = [1; N];
    let mut i = 0;
    let mut current_deck_size = deck_size;

    while i < N {
        arr[i] *= count_combination(current_deck_size as u64, deal_hole_street[i] as u64) as i32;
        current_deck_size -= deal_hole_street[i] as usize;

        arr[i] *= count_combination(current_deck_size as u64, deal_board_street[i] as u64) as i32;
        current_deck_size -= deal_board_street[i] as usize;

        i += 1;
    }
    arr
}

pub trait Hand: Deal + Deck {
    const DEAL_HAND_COMBINATION_STREET: &'static [i32];

    // street : 0...NUM_STREET
    fn change_hole_street(street: usize, hand: &mut [u8], cards: &[u8]) {
        hand[..Self::HOLE_LEN_STREET[street]]
            .copy_from_slice(&cards[..Self::HOLE_LEN_STREET[street]]);
    }

    fn deal_card_street(new_street: usize, hand: &mut [u8], hole_add: &[u8], board_add: &[u8]) {
        // old:[1,2|3,4,5] ha:6, ba:7
        let start = Self::HAND_LEN_STREET[new_street]
            - (Self::DEAL_HOLE_STREET[new_street] + Self::DEAL_BOARD_STREET[new_street]) as usize;
        let end = Self::HAND_LEN_STREET[new_street];

        // mid:[1,2|3,4,5,7,6]
        hand[start..end].copy_from_slice(
            board_add
                .iter()
                .chain(hole_add.iter())
                .map(|&x| x)
                .collect::<Vec<_>>()
                .as_slice(),
        );

        // res:[1,2,6|3,4,5,7]
        hand[start..end].rotate_right(Self::DEAL_HOLE_STREET[new_street] as usize);
    }

    fn change_board_street(street: usize, hand: &mut [u8], cards: &[u8]) {
        hand[Self::HOLE_LEN_STREET[street]..Self::HAND_LEN_STREET[street]]
            .copy_from_slice(&cards[..Self::BOARD_LEN_STREET[street]]);
    }

    fn change_add_street(street: usize, hand: &mut [u8], hole_add: &[u8], board_add: &[u8]) {
        // hole
        hand[(Self::HOLE_LEN_STREET[street] - Self::DEAL_HOLE_STREET[street] as usize)
            ..Self::HOLE_LEN_STREET[street]]
            .copy_from_slice(&hole_add[..{ Self::DEAL_HOLE_STREET[street] as usize }]);

        // board
        hand[(Self::HAND_LEN_STREET[street] - Self::DEAL_BOARD_STREET[street] as usize)
            ..Self::HAND_LEN_STREET[street]]
            .copy_from_slice(&board_add[..{ Self::DEAL_BOARD_STREET[street] as usize }]);
    }

    fn invalid_next_street_hand(new_street: usize, hand: &mut [u8]) {
        Self::deal_card_street(
            new_street,
            hand,
            vec![u8::MAX; Self::DEAL_HOLE_STREET[new_street] as usize].as_slice(),
            vec![u8::MAX; Self::DEAL_BOARD_STREET[new_street] as usize].as_slice(),
        );
    }

    fn truncate_hand(current_street: usize, pre_street: usize, hand: &[u8]) -> Vec<u8> {
        // old:[1,2,6|3,4,5,7] ha:6, ba:7
        let pre_hole_end = Self::HOLE_LEN_STREET[pre_street];
        let current_board_start = Self::HOLE_LEN_STREET[current_street];

        hand[..pre_hole_end]
            .iter()
            .chain(
                hand[current_board_start..{
                    current_board_start + Self::BOARD_LEN_STREET[pre_street] as usize
                }]
                    .iter(),
            )
            .cloned()
            .collect::<Vec<u8>>()
    }
}
