use super::component::*;

// DECK
pub const ROYAL_DECK: [u8; 20] = [
    0, 1, 2, 3, // { 32, 33, 34, 35    // T
    4, 5, 6, 7, // , 36, 37, 38, 39    // J
    8, 9, 10, 11, // , 40, 41, 42, 43    // Q
    12, 13, 14, 15, // , 44, 45, 46, 47    // K
    16, 17, 18, 19, // , 48, 49, 50, 51}   // A
];

pub const STANDARD_DECK: [u8; 52] = [
    0, 1, 2, 3, // 2
    4, 5, 6, 7, // 3
    8, 9, 10, 11, // 4
    12, 13, 14, 15, // 5
    16, 17, 18, 19, // 6
    20, 21, 22, 23, // 7
    24, 25, 26, 27, // 8
    28, 29, 30, 31, // 9
    32, 33, 34, 35, // T
    36, 37, 38, 39, // J
    40, 41, 42, 43, // Q
    44, 45, 46, 47, // K
    48, 49, 50, 51, // A
];

pub const NUMERAL_DECK: [u8; 40] = [
    0, 1, 2, 3, // 2
    4, 5, 6, 7, // 3
    8, 9, 10, 11, // 4
    12, 13, 14, 15, // 5
    16, 17, 18, 19, // 6
    20, 21, 22, 23, // 7
    24, 25, 26, 27, // 8
    28, 29, 30, 31, // 9
    32, 33, 34, 35, // T
    36, 37, 38, 39, // A
];

// DEAL
pub const DEAL21: DealConfig<2> = DealConfig::<2> {
    deal_hole_street: [2, 0],
    deal_board_street: [0, 1],
};

pub const DEAL22: DealConfig<2> = DealConfig::<2> {
    deal_hole_street: [2, 0],
    deal_board_street: [0, 2],
};

pub const DEAL23: DealConfig<2> = DealConfig::<2> {
    deal_hole_street: [2, 0],
    deal_board_street: [0, 3],
};

pub const DEAL111: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [1, 0, 0],
    deal_board_street: [0, 1, 1],
};

pub const DEAL211: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [2, 0, 0],
    deal_board_street: [0, 1, 1],
};

pub const DEAL121: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [1, 0, 0],
    deal_board_street: [0, 2, 1],
};

pub const DEAL221: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [2, 0, 0],
    deal_board_street: [0, 2, 1],
};

pub const DEAL222: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [2, 0, 0],
    deal_board_street: [0, 2, 2],
};

pub const DEAL223: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [2, 0, 0],
    deal_board_street: [0, 2, 3],
};

pub const DEAL231: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [2, 0, 0],
    deal_board_street: [0, 3, 1],
};

pub const DEAL232: DealConfig<3> = DealConfig::<3> {
    deal_hole_street: [2, 0, 0],
    deal_board_street: [0, 3, 2],
};

pub const DEAL2311: DealConfig<4> = DealConfig::<4> {
    deal_hole_street: [2, 0, 0, 0],
    deal_board_street: [0, 3, 1, 1],
};

pub const DEAL2111: DealConfig<4> = DealConfig::<4> {
    deal_hole_street: [2, 0, 0, 0],
    deal_board_street: [0, 1, 1, 1],
};

pub const DEAL2211: DealConfig<4> = DealConfig::<4> {
    deal_hole_street: [2, 0, 0, 0],
    deal_board_street: [0, 2, 1, 1],
};

//2+2
use byteorder::LittleEndian;
use byteorder::ReadBytesExt;
use itertools::Itertools;
use once_cell::sync::OnceCell;
use std::fs::File;
use std::path::Path;

const SIZE_2PLUS2: usize = 32487834;

static TABLE_2PLUS2: OnceCell<Vec<i32>> = OnceCell::new();

pub fn initial_2plus2() {
    TABLE_2PLUS2.get_or_init(|| {
        let path = Path::new("data/2plus2/HandRanks.dat");
        let display = path.display();

        let mut file = match File::open(&path) {
            // `io::Error` 的 `description` 方法返回一个描述错误的字符串。
            Err(why) => panic!("couldn't open {}: {:?}", display, why),
            Ok(file) => file,
        };

        let mut buffer: Vec<i32> = vec![0; SIZE_2PLUS2];
        match file.read_i32_into::<LittleEndian>(buffer.as_mut_slice()) {
            Err(_) => panic!("读取 2 + 2 查询表位数不对"),
            _ => {}
        };
        buffer
    });
}

// showdown my card

pub trait Poker2Plus2: Deal + Deck + Hand {
    fn rank_showdown_2plus2(hand: &[u8]) -> i32 {
        let mut rank: i32 = 53;
        for i in 0..Self::HAND_LEN {
            rank = TABLE_2PLUS2.get().unwrap()
                [(rank + hand[i] as i32 + 1 + (52 - Self::DECK.len() as i32)) as usize]
        }
        if Self::HAND_LEN < 7 {
            rank = TABLE_2PLUS2.get().unwrap()[rank as usize];
        }
        rank
    }

    fn showdown_winning_distrubution_2plus2(hand: &[u8]) -> [i64; LTW] {
        let left_card: Vec<u8> =
            Vec::from_iter(Self::DECK.iter().filter(|&&x| !hand.contains(&x)).cloned());

        let mut feature = [0 as i64; LTW];

        let mut base_rank = 53;
        for i in Self::HOLE_LEN_STREET[{ Self::NUM_STREET - 1 } as usize]..Self::HAND_LEN {
            base_rank = TABLE_2PLUS2.get().unwrap()
                [(base_rank + hand[i] as i32 + 1 + (52 - Self::DECK.len() as i32)) as usize]
        }

        let mut my_rank = base_rank;
        for i in 0..Self::HOLE_LEN_STREET[{ Self::NUM_STREET - 1 } as usize] {
            my_rank = TABLE_2PLUS2.get().unwrap()
                [(my_rank + hand[i] as i32 + 1 + (52 - Self::DECK.len() as i32)) as usize]
        }
        if Self::HAND_LEN < 7 {
            my_rank = TABLE_2PLUS2.get().unwrap()[my_rank as usize];
        }

        let mut opponent_hand = Vec::from(hand);
        let opponent_hole_iter = left_card
            .iter()
            .cloned()
            .combinations(Self::HOLE_LEN_STREET[{ Self::NUM_STREET - 1 } as usize]);
        for opponent_hole in opponent_hole_iter {
            Self::change_hole_street(
                { Self::NUM_STREET - 1 } as usize,
                opponent_hand.as_mut_slice(),
                opponent_hole.as_slice(),
            );
            let mut opponent_rank = base_rank;
            for i in 0..Self::HOLE_LEN_STREET[{ Self::NUM_STREET - 1 } as usize] {
                opponent_rank = TABLE_2PLUS2.get().unwrap()[(opponent_rank
                    + opponent_hand[i] as i32
                    + 1
                    + (52 - Self::DECK.len() as i32))
                    as usize]
            }
            if Self::HAND_LEN < 7 {
                opponent_rank = TABLE_2PLUS2.get().unwrap()[opponent_rank as usize];
            }

            if my_rank < opponent_rank {
                feature[0] += 1;
            } else if my_rank == opponent_rank {
                feature[1] += 1;
            } else {
                feature[2] += 1;
            }
        }
        feature
    }
}

// buitin games
pub mod numeral211;