#pragma once
#include "overall_define.h"
#include "template/domain_independent/showdown_histogram.h"

const int MAX_STREETS = 8;

template<typename Poker>
class Hand;

template<typename Poker>
class HandBase{
protected:
    static inline bool initialized_ = false;
public:
    static inline const bool &initialized = initialized_;
    using Poker_t = Poker;
    HandBase(const type::card_t* hole, const type::card_t* board, int round);
    ~HandBase();

    const type::card_t* get_data() const;
    int get_round() const;
    // uint64_t get_perfect_isomorphism() const;
    // uint64_t get_imperfect_isomorphism() const;

    uint64_t get_hand_index() const;
    void hand_unindex(uint64_t idx, int round);
    uint64_t get_hand_isomorphism(int recall_from) const;
    void hand_unisomorphism(uint64_t iso, int round, int recall_from);

    void change_hole(const type::card_t* hole);
    void change_board(const type::card_t* board);
    void add_deal(const type::card_t* cards);
    void add_deal(const type::card_t* new_round_hole, const type::card_t* new_round_board);
protected:
    // void compute_isomorphism_();
public:

    //子类特例化
    static void init();
    static void free();
    // static void perfect_hand_unindex(uint64_t hand_isomorphism, int round, type::card_t* hand);
    // static void imperfect_hand_unindex(uint64_t hand_isomorphism, int round, type::card_t* hand);
    // static uint64_t compute_perfect_isomorphism(int round, const type::card_t* hand);
    // static uint64_t compute_imperfect_isomorphism(int round, const type::card_t* hand);
    static void hand_unisomorphism(uint64_t hand_isomorphism, int round, int recall_from, type::card_t* hand);
    static void hand_unindex(uint64_t hand_index, int round, type::card_t* hand);
    static uint64_t compute_hand_isomorphism(int round, int recall_from, const type::card_t* hand);
    static uint64_t compute_hand_index(int round, const type::card_t* hand);
    static uint64_t get_isomorphism_size(int round, int recall_from);

    static Hand<Poker_t> from_string(const std::string str);

protected:
    type::card_t hand[Poker_t::hand_len[Poker_t::num_rounds-1]];// |hole, baord|
    int round;

public:
    static const std::array<std::array<uint8_t, MAX_STREETS>, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> isomorphism_configs;
    static const std::array<int, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> isomorphism_stages;
};

inline int id_2d_to_1d(int street, int recall_from) {
    assert(recall_from <= street);
    return street * (street + 1) / 2 + recall_from;
}

// round是发牌后的轮次
template<typename Poker_t>
void add_deal(type::card_t* hand, const type::card_t* new_round_cards, int round);

template<typename Poker_t>
void add_deal(type::card_t* hand, const type::card_t* new_round_hole, const type::card_t* new_round_board, int round);

template<typename Poker_t>
inline constexpr std::array<std::array<uint8_t, MAX_STREETS>, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> get_isomorphism_configs() {
    static_assert(std::is_base_of<PokerBase, Poker_t>::value && !std::is_same<PokerBase, Poker_t>::value, "get_isomorphism_configs函数模板中Poker_t必须是PokerBase的派生类");
    std::array<std::array<uint8_t, MAX_STREETS>, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> isomorphism_configs;

    for(int cur_round = 0; cur_round < Poker_t::num_rounds; ++cur_round){
        uint8_t sum_hole = 0;
        uint8_t sum_board = 0;

        for(int recall_round = 0; recall_round <= cur_round; ++recall_round){
            int id_1d = cur_round * (cur_round+1)/2 + recall_round;

            sum_hole += Poker_t::deal_hole_round[recall_round];
            sum_board += Poker_t::deal_board_round[recall_round];

            //hole与board的发牌分别计数，以便后面拼接起来
            uint8_t temp_chole[MAX_STREETS]{0};
            uint8_t temp_cboard[MAX_STREETS]{0};
            int chole_len = 0;
            int cboard_len = 0;

            // 计数
            if (sum_hole > 0) {
                temp_chole[chole_len] = sum_hole;
                chole_len += 1;
            }
            if (sum_board > 0) {
                temp_cboard[cboard_len] = sum_board;
                cboard_len += 1;
            }

            for (int i = recall_round + 1; i <= cur_round; ++i){
                if (Poker_t::deal_hole_round[i] > 0) {
                    temp_chole[chole_len] += Poker_t::deal_board_round[i];
                    chole_len += 1;
                }
                if (Poker_t::deal_board_round[i] > 0) {
                    temp_cboard[cboard_len] += Poker_t::deal_board_round[i];
                    cboard_len += 1;
                }
            }

            // 拼接
            int i = 0;
            while (i < chole_len) {
                isomorphism_configs[id_1d][i] = temp_chole[i];
                i += 1;
            }
            while (i < chole_len + cboard_len) {
                isomorphism_configs[id_1d][i] = temp_cboard[i - chole_len];
                i += 1;
            }
        }
    }
    return isomorphism_configs;
}

template<typename Poker_t>
inline constexpr std::array<int, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> get_isomorphism_stages(){
    static_assert(std::is_base_of<PokerBase, Poker_t>::value && !std::is_same<PokerBase, Poker_t>::value, "get_isomorphism_stages函数模板中Poker_t必须是PokerBase的派生类");
    std::array<int, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> isomorphism_stages;

    for(int cur_round = 0; cur_round < Poker_t::num_rounds; ++cur_round){
        uint8_t sum_hole = 0;
        uint8_t sum_board = 0;

        for(int recall_round = 0; recall_round <= cur_round; ++recall_round){
            int id_1d = cur_round * (cur_round+1)/2 + recall_round;

            sum_hole += Poker_t::deal_hole_round[recall_round];
            sum_board += Poker_t::deal_board_round[recall_round];

            //hole与board的发牌分别计数，以便后面拼接起来
            int stage_len = 0;

            // 计数
            if (sum_hole > 0) {
                stage_len += 1;
            }
            if (sum_board > 0) {
                stage_len += 1;
            }

            for (int i = recall_round + 1; i <= cur_round; ++i){
                if (Poker_t::deal_hole_round[i] > 0) {
                    stage_len += 1;
                }
                if (Poker_t::deal_board_round[i] > 0) {
                    stage_len += 1;
                }
            }

            // 拼接
            isomorphism_stages[id_1d] = stage_len;
            assert(stage_len < MAX_STREETS);
        }
    }
    return isomorphism_stages;
}