use itertools::Itertools;
use std::backtrace;
use std::borrow::Borrow;
use std::borrow::BorrowMut;
use std::cmp::min;
use std::collections::HashMap;
use std::collections::HashSet;
use std::hash::Hash;
// use std::cell::{RefCell, Ref};


use crate::game::component::*;
use crate::hand_isomorphism::hand_index_last;
use crate::hand_isomorphism::{hand_indexer_t, uint_fast32_t};
use crate::hand_isomorphism::{hand_unindex};
use std::marker::PhantomData;

use mysql::*;
use mysql::prelude::*;

pub mod db_util;
use db_util::DbConnect;
use lmdb::{Environment};

use std::cell::RefCell;

enum DistributionEnum{
    WinningArray,
    PotentialVec,
    TraceVec
}

trait DistributionType{
    type InnerType: Eq + Hash + Clone;
    type Type : Eq + Hash + Clone + Ord + BorrowMut<[Self::InnerType]> + Borrow<[Self::InnerType]> + 'static;
    const TYPE_ENUM: DistributionEnum;

    fn new<T>(street_sentinel:i32)->Self::Type
        where T: Singleton + Hand + WaughTrait + ShowdownRanker + 'static;
    fn data_clansing(data : &mut Self::Type);

}

struct WinningDistribution;
impl DistributionType for WinningDistribution{
    type InnerType = i64;
    type Type = [i64; LTW];
    const TYPE_ENUM: DistributionEnum = DistributionEnum::WinningArray;
    fn new<T>(street_sentinel:i32)->Self::Type 
        where T: Singleton + Hand + WaughTrait + ShowdownRanker + 'static
    {
        [0i64; LTW]
    }

    fn data_clansing(data : &mut Self::Type){}
}

struct PotentialDistribution;
impl DistributionType for PotentialDistribution
{
    type InnerType = u32;
    type Type = Vec<u32>;
    const TYPE_ENUM: DistributionEnum = DistributionEnum::PotentialVec;
    fn new<T>(street_sentinel:i32)->Self::Type 
        where T: Singleton + Hand + WaughTrait + ShowdownRanker + 'static
    {
        let street = street_sentinel as usize - 1;
        Vec::with_capacity(<T as Hand>::DEAL_HAND_COMBINATION_STREET[street] as usize)
    }

    fn data_clansing(data : &mut Self::Type){
        data.sort();
    }
}

struct TraceDistribution;
impl DistributionType for TraceDistribution{
    type InnerType = u32;
    type Type = Vec<u32>;
    const TYPE_ENUM: DistributionEnum = DistributionEnum::TraceVec;
    fn new<T>(street_sentinel:i32)->Self::Type 
        where T: Singleton + Hand + WaughTrait + ShowdownRanker + 'static
    {
        Vec::with_capacity(street_sentinel as usize)
    }

    fn data_clansing(data : &mut Self::Type){}
}

#[derive(Clone)]
struct TransferData<D:Eq + Hash + Clone + Ord>{
    distribution_to_id: HashMap<D, u32>,
    id_to_distribution: Vec<D>,
    xriso_to_distribution_id: Option<Vec<u32>>
}

impl<D:Eq + Hash + Clone + Ord> TransferData<D> {
    pub fn new()->Self{
        Self { distribution_to_id: HashMap::<D, u32>::new(), id_to_distribution: Vec::<D>::new(), xriso_to_distribution_id: None }
    }
}

pub struct Featurizer<T> {

    nriso_winning : RefCell<Vec<TransferData<[i64; LTW]>>>, // never recall
    nriso_potential: RefCell<Vec<TransferData<Vec<u32>>>>,
    priso_winning_trace: RefCell<Vec<Vec<TransferData<Vec<u32>>>>>,// partial recall
    priso_potential_trace: RefCell<Vec<Vec<TransferData<Vec<u32>>>>>,// partial recall

    env: Environment,

    _marker:PhantomData<T>,
}
const MYSQL_URL: &str = "mysql://root:root@localhost:3306/poker";
impl<T> Featurizer<T> 
    where T: Singleton + Hand + WaughTrait + ShowdownRanker + 'static
{

    pub fn new() -> Self {
        #[cfg(feature = "test_print")]
        println!("new instance!");
        match <Self as DbConnect>::clear_and_init_env(std::format!("data/{}/database/", T::GAME_NAME).as_str()) {
            Ok(env) => {
                Self {
                    nriso_winning : RefCell::new(vec![TransferData::<[i64; LTW]>::new(); T::NUM_STREET.try_into().unwrap()]), // never recall
                    nriso_potential: RefCell::new(vec![TransferData::<Vec<u32>>::new(); T::NUM_STREET.try_into().unwrap()]),
                    priso_winning_trace : RefCell::new((0..{T::NUM_STREET as usize}).map(|isz| vec![TransferData::<Vec<u32>>::new(); isz]).collect::<Vec<Vec<TransferData<Vec<u32>>>>>()),
                    priso_potential_trace : RefCell::new((0..{T::NUM_STREET as usize}).map(|isz| vec![TransferData::<Vec<u32>>::new(); isz]).collect::<Vec<Vec<TransferData<Vec<u32>>>>>()),
        
                    env,
                    _marker: PhantomData,
                    
                }
            },
            Err(e) => {
                println!("Error:{}", e);
                panic!();
            }
        }
    }

/// 1. 完成street_imperfect_recall_isomorphism_size个hand的遍历
/// 2. 为每个hand生成distribution
/// 3. 将所有distribution通过set去重
/// 4. 为通过去重的distribution建立dist_to_id与id_to_dist的映射
/// 5. 用数据库或向量实现nriso_to_dist_id功能
/// 6. 第二个参数中的闭包实现从hand生成distribution的功能，剩下的各种变体都是围绕这个闭包的变化讨论的
    fn handle_partial_recall_distribution<'a, D, F, FR>(&'a self, street_sentinel: i32, recall_from_sentinel: i32, hand_to_distribution:F, save_to_db: Option<FR>)
            -> std::result::Result<TransferData<D::Type>, Box<dyn std::error::Error>> 
        where D : DistributionType,
        F: Fn(&[u8]) -> D::Type + 'a ,
        FR: FnOnce(Box<dyn Fn(u32)->u32 + 'a>, u32) + 'a,
    {
        assert!(recall_from_sentinel >= 1);
        assert!(street_sentinel >= recall_from_sentinel);

        let game : &'static T = T::instance().as_ref();
        let street = street_sentinel as usize - 1;
        let recall_from = recall_from_sentinel as usize -1;

        // let street_x_recall_indexer = &game.get_game_indexer().street_x_recall_indexers_1d[id_2d_to_1d(street, recall_from)];
        let stage_sentinel = T::INDEXER_STAGES_1D[id_2d_to_1d(street, recall_from)];
        let xname = match ((recall_from_sentinel == 1), (recall_from_sentinel == street_sentinel)){//
            (true, true) => "perfect&never",
            (true,false) => "perfect",
            (false, true) =>"never",
            _=>"partial"
        };

        let street_x_recall_isomorphism_size:u64 = game.hand_isomorphism_size_street(street, recall_from);

        assert!(0 != street_x_recall_isomorphism_size);

        #[cfg(feature = "test_print")]
        {
            println!("===================================================");
            println!("street: {}", street);
            println!("{} recall isomorphism size: {}", xname, street_x_recall_isomorphism_size);
        }

        let mut street_distribution_set = HashSet::<D::Type>::new();
        let mut max_id:u32 = 0;

        // 生成分布然后去重
        for xriso in 0..street_x_recall_isomorphism_size {
            let mut hand = vec![0 as u8; T::HAND_LEN];
            game.hand_unindexify(xriso, street, recall_from, hand.as_mut());
            let street_distribution = hand_to_distribution(hand.as_slice());
            
            if !street_distribution_set.contains(street_distribution.borrow()){
                street_distribution_set.insert(street_distribution.clone());

                max_id += 1;
            }
        }

        // 去重后的分布，给分配唯一的id，为了这个id不受hash函数的影响，使用sort按照分布的字典序赋予id
        let mut id_to_street_distribution : Vec<D::Type> = Vec::new();
        id_to_street_distribution.extend(street_distribution_set.iter().cloned());
        id_to_street_distribution.sort();

        #[cfg(feature = "test_print")]
        println!("number of unduplicated street distribution: {}", max_id);

        // 辅助映射，使得用户可以通过分布查询分布的id
        let mut street_distribution_to_id:HashMap<D::Type, u32> = HashMap::new();
        street_distribution_to_id.extend(id_to_street_distribution.iter().cloned().enumerate().map(|(id, street_distribution)|(street_distribution, id as u32)));


        // 构造由xriso获取分布的闭包，过程是xriso -> dist -> dist_id；这个闭包最后用来存数据库或priso_to_distribution_id向量（这个向量体量很大）
        let xriso_to_dist_id  = Box::new({

            let street_x_recall_indexer = &(*street_x_recall_indexer);
            let stage_sentinel = stage_sentinel.clone();
            let hand_to_distribution = hand_to_distribution;
            let street_distribution_to_id = street_distribution_to_id.clone();
            move |xriso : u32| {
                let mut hand = vec![0 as u8; T::HAND_LEN];
                game.hand_unindexify(xriso, street, recall_from, hand.as_mut());
                let street_distribution = hand_to_distribution(hand.as_slice());

                match street_distribution_to_id.get(street_distribution.borrow()) {
                    Some(id) =>{*id},
                    None => { panic!("找不到distribution对应的id");}
                }
            }
        });

        let xriso_to_distribution_id = {
            #[cfg(feature = "db_inloop")]
            {None}
            #[cfg(not(feature = "db_inloop"))]
            {Some((0..street_x_recall_isomorphism_size as u32).map(|i| xriso_to_dist_id(i)).collect())}
        };

        if let Some(save_to_db) = save_to_db{
            save_to_db(xriso_to_dist_id, street_x_recall_isomorphism_size as u32);
        }


        Ok(TransferData::<D::Type>{
            distribution_to_id: street_distribution_to_id,
            id_to_distribution: id_to_street_distribution,
            xriso_to_distribution_id
        })

    }

/// 1. 非showdown轮次distribution的构造
/// 2. 涉及至少两个street：street + next_street
/// 3. hand发牌到下一轮次会出现n个next_hand，distribution就是这n个next_hand情况的计算结果
/// 4. 第二个闭包决定next_hand的next_dist是哪种类型，可能的由potential或winning，映射到id
/// 5. 第三个闭包决定n个next_hand的dist_id如何计算出distribution，可能的有push(potential)或accumulate(winning)
    fn handle_non_showdown_distribution<'a, D, F1, F2, FR>(&'a self, street_sentinel: i32, next_hand_to_distribution_id: F1, distribution_generic_accmulate: F2, save_to_db:Option<FR>)
            -> std::result::Result<TransferData<D::Type>, Box<dyn std::error::Error>>
        where D : DistributionType,
              F1 : Fn(&mut [u8], &[u8], &[u8]) -> u32 +'a,
              F2 : Fn(&mut D::Type, u32) + 'a,
              FR: FnOnce(Box<dyn Fn(u32)->u32 + 'a>, u32) + 'a,
    {
        assert!(T::NUM_STREET > 1);
        assert!(street_sentinel + 1 <= T::NUM_STREET);

        let build_distribution_from_potential_hands = {

            let next_street_sentinel = street_sentinel + 1;
            let next_street = next_street_sentinel as usize - 1;
    
            let street = street_sentinel as usize - 1;
            let street_sentinel = street_sentinel;

            let distribution_generic_accmulate = distribution_generic_accmulate;
            let next_hand_to_distribution_id = next_hand_to_distribution_id;

            move |hand:&[u8]| ->D::Type {
                let left_cards : Vec<u8> = Vec::from_iter(
                    T::DECK.iter().filter(
                        |&&x| !hand.contains(&x)
                    ).cloned()
                );

                let mut distribution = D::new::<T>(street_sentinel);

                let mut next_hand = Vec::from(hand);
                T::invalid_next_street_hand(next_street, next_hand.as_mut_slice());

                match (T::DEAL_HOLE_STREET[next_street] as u8, T::DEAL_BOARD_STREET[next_street] as u8) {
                    (0, 0) => {panic!("分组组合都是0");},
                    (0, _) => {
                        let hole_add = Vec::new();
                        left_cards
                        .iter()
                        .cloned()
                        .combinations(T::DEAL_BOARD_STREET[next_street] as usize)
                        .for_each(|board_add| distribution_generic_accmulate(&mut distribution, next_hand_to_distribution_id(next_hand.as_mut_slice(), hole_add.as_slice(), board_add.as_slice())));
                    }, // 第二位肯定不是0
                    (_, 0) => {
                        let board_add = Vec::new();
                        left_cards
                        .iter()
                        .cloned()
                        .combinations(T::DEAL_HOLE_STREET[next_street] as usize)
                        .for_each(|hole_add| distribution_generic_accmulate(&mut distribution, next_hand_to_distribution_id(next_hand.as_mut_slice(), hole_add.as_slice(), board_add.as_slice())));
                    }, // 第一位肯定不是0
                    (_, _) => {
                        left_cards
                        .iter()
                        .cloned()
                        .combinations(T::DEAL_HOLE_STREET[next_street] as usize)
                        .for_each(|hole_add| {
                            left_cards.iter().filter(|&x| !hole_add.contains(x)).cloned().collect::<Vec<u8>>() // left_left_cards
                            .iter()
                            .cloned()
                            .combinations(T::DEAL_BOARD_STREET[next_street] as usize)
                            .for_each(|board_add| distribution_generic_accmulate(&mut distribution, next_hand_to_distribution_id(next_hand.as_mut_slice(), hole_add.as_slice(), board_add.as_slice())));
                        });
                    }, // 都不是0
                }
                D::data_clansing(&mut distribution);
                distribution
            }
        };

        self.handle_partial_recall_distribution::<D, _, _>(street_sentinel, street_sentinel, build_distribution_from_potential_hands, save_to_db)
    }

/// next_hand_to_distribution_id: potential
/// distribution_generic_accmulate: push
    fn handle_pre_non_showdown_potential_distribution(&self, street_sentinel: i32) {
        assert!(street_sentinel < T::NUM_STREET - 1); //至少要小两轮

        let next_street_sentinel = street_sentinel + 1;
        let next_street = next_street_sentinel as usize - 1;

        let street = street_sentinel as usize - 1;

        let mut potential_distribution_generic_accmulate_next_potential = |potential_distribution: &mut <PotentialDistribution as DistributionType>::Type, next_potential_distribution_id:u32| {
            potential_distribution.push(next_potential_distribution_id);
        };

        let next_hand_to_potential_distribution_id = {

            let next_street_sentinel = street_sentinel + 1;
            let next_street = next_street_sentinel as usize - 1;
    
            let street = street_sentinel as usize - 1;
            let street_sentinel = street_sentinel;

            let game : &'static T = T::instance().as_ref();

            // let never_recall_indexer = &game.get_game_indexer().street_x_recall_indexers_1d[id_2d_to_1d(next_street, next_street)];

            move |next_hand:&mut [u8], hole_add:&[u8], board_add:&[u8]| ->u32 {
                T::change_add_street(next_street, next_hand, hole_add, board_add);
    
                let next_nriso = game.hand_indexify(next_hand, next_street, next_street);
    
                // 从next_nriso 拿到 win_dist_id
                #[cfg(feature = "db_inloop")] {
                    self.query_ptl_dist_id_with_nriso(next_nriso, next_street_sentinel).unwrap()
                }
                #[cfg(not(feature = "db_inloop"))] {
                    self.nriso_potential.borrow()[next_street].xriso_to_distribution_id.as_ref().unwrap()[next_nriso as usize]
                }
            }
        };

        let save_to_db = Some(
            {
                let street_sentinel = street_sentinel;
                move|nriso_to_ptl_dist_id/*这个东西一定是box<dyn>*/ , n|{
                    if let Err(e) = self.save_nriso_to_ptl_dist_id(nriso_to_ptl_dist_id, n, street_sentinel){
                        println!("Error:{}", e);
                    }
                }
            }
        );

        self.nriso_potential.borrow_mut()[street] 
        = self.handle_non_showdown_distribution::<PotentialDistribution, _, _, _>(street_sentinel, next_hand_to_potential_distribution_id, potential_distribution_generic_accmulate_next_potential, save_to_db).unwrap();

    }

/// next_hand_to_distribution_id: winning
/// distribution_generic_accmulate: push
    fn handle_pre_showdown_potential_distribution(&self) {

        let mut potential_distribution_generic_accmulate_showdown_winning = |potential_distribution: &mut <PotentialDistribution as DistributionType>::Type, showdown_winning_distribution_id:u32| {
            potential_distribution.push(showdown_winning_distribution_id);
        };

        let showdown_hand_to_winning_distribution_id = {

            let next_street_sentinel = T::NUM_STREET;
            let next_street = next_street_sentinel as usize - 1;
    
            let street_sentinel = T::NUM_STREET - 1;
            let street = street_sentinel as usize - 1;
    
            let game : &'static T = T::instance().as_ref();

            // let never_recall_indexer = &game.get_game_indexer().street_x_recall_indexers_1d[id_2d_to_1d(next_street, next_street)];

            move |next_hand:&mut [u8], hole_add:&[u8], board_add:&[u8]| ->u32 {
                T::change_add_street(next_street, next_hand, hole_add, board_add);
    
                let next_nriso = game.hand_indexify(next_hand, next_street, next_street);
    
                // 从next_nriso 拿到 win_dist_id
                #[cfg(feature = "db_inloop")] {
                    self.query_win_dist_id_with_nriso(next_nriso, next_street_sentinel).unwrap()
                } 
                #[cfg(not(feature = "db_inloop"))] {
                    self.nriso_winning.borrow()[next_street].xriso_to_distribution_id.as_ref().unwrap()[next_nriso as usize]
                }
            }
        };

        let save_to_db = Some(
            {
                let street_sentinel = T::NUM_STREET - 1;
                move|nriso_to_ptl_dist_id/*这个东西一定是box<dyn>*/ , n|{
                    if let Err(e) = self.save_nriso_to_ptl_dist_id(nriso_to_ptl_dist_id, n, street_sentinel){
                        println!("Error:{}", e);
                    }
                }
            }
        );

        let street_sentinel = T::NUM_STREET - 1;
        let street = street_sentinel as usize - 1;
        self.nriso_potential.borrow_mut()[street]
        = self.handle_non_showdown_distribution::<PotentialDistribution, _, _, _>(street_sentinel, showdown_hand_to_winning_distribution_id, potential_distribution_generic_accmulate_showdown_winning, save_to_db).unwrap();

    }

/// next_hand_to_distribution_id: winning
/// distribution_generic_accmulate: accumulate
    fn handle_non_showdown_winning_distribution(&self, street_sentinel:i32) {

        let street = street_sentinel as usize - 1;

        let mut winning_distribution_generic_accmulate_next_winning = {

            let next_street = street_sentinel as usize;
            move |winning_distribution: &mut <WinningDistribution as DistributionType>::Type, next_winning_distribution_id:u32| {
                for (acc_j, &dist_j) in winning_distribution.iter_mut().zip(
                    self.nriso_winning.borrow()[next_street].id_to_distribution
                    .get(next_winning_distribution_id as usize)
                    .unwrap()
                    .iter()
                ) {
                    *acc_j += dist_j;
                }
            }
        };

        let next_hand_to_winning_distribution_id = {
            let next_street_sentinel = street_sentinel + 1;
            let next_street = next_street_sentinel as usize - 1;
            let game : &'static T = T::instance().as_ref();
            // let never_recall_indexer = &game.get_game_indexer().street_x_recall_indexers_1d[id_2d_to_1d(next_street, next_street)];

            move |next_hand:&mut [u8], hole_add:&[u8], board_add:&[u8]| ->u32 {
                T::change_add_street(next_street, next_hand, hole_add, board_add);

                let next_nriso = game.hand_indexify(next_hand, next_street, next_street);

                // 从next_nriso 拿到 win_dist_id
                #[cfg(feature = "db_inloop")] {
                    self.query_win_dist_id_with_nriso(next_nriso, next_street_sentinel).unwrap()
                } 
                #[cfg(not(feature = "db_inloop"))] {
                    self.nriso_winning.borrow()[next_street].xriso_to_distribution_id.as_ref().unwrap()[next_nriso as usize]
                }
            }
        }; 

        let save_to_db = Some(
            {
                let street_sentinel = street_sentinel;
                move |nriso_to_win_dist_id/*这个东西一定是box<dyn>*/ , n|{
                    if let Err(e) = self.save_nriso_to_win_dist_id(nriso_to_win_dist_id, n, street_sentinel){
                        println!("Error:{}", e);
                    }
                }
            }
        );


        self.nriso_winning.borrow_mut()[street]
        = self.handle_non_showdown_distribution::<WinningDistribution, _, _, _>(street_sentinel, next_hand_to_winning_distribution_id, winning_distribution_generic_accmulate_next_winning, save_to_db).unwrap();
    }

    /// 最简单的情况hand_to_distribution就是game中定义的showdown牌到dist
    fn handle_showdown_winning_distribution(&self){

        let street = T::NUM_STREET as usize - 1;
        
        let save_to_db = Some(
            {
                |nriso_to_win_dist_id/*这个东西一定是box<dyn>*/ , n|{
                    if let Err(e) = self.save_nriso_to_win_dist_id(nriso_to_win_dist_id, n, T::NUM_STREET){
                        println!("Error:{}", e);
                    }
                }
            }
        );
    
        self.nriso_winning.borrow_mut()[street] =
        self.handle_partial_recall_distribution::<WinningDistribution, _, _>(T::NUM_STREET, T::NUM_STREET, T::showdown_winning_distrubution, save_to_db).unwrap();
    }

    pub fn handle_street_winning_distribution(&self, street_sentinel:i32){
        assert!(street_sentinel > 0);
        assert!(street_sentinel <= T::NUM_STREET);

        if street_sentinel == T::NUM_STREET {
            self.handle_showdown_winning_distribution();
        } else {
            self.handle_non_showdown_winning_distribution(street_sentinel);
        }
    }

    pub fn handle_street_potential_distribution(&self, street_sentinel:i32){
        assert!(street_sentinel > 0);
        assert!(street_sentinel < T::NUM_STREET);

        if street_sentinel == T::NUM_STREET-1 {
            self.handle_pre_showdown_potential_distribution();
        } else {
            self.handle_pre_non_showdown_potential_distribution(street_sentinel);
        }
    }

    pub fn handle_street_winning_trace_distribution<'a>(&'a self, street_sentinel: i32, recall_from_sentinel: i32) // w trace
    {
        assert!(recall_from_sentinel >= 1);
        assert!(street_sentinel > recall_from_sentinel);
        
        let game : &'static T = T::instance().as_ref();

        let hand_to_trace = {
            let street_sentinel = street_sentinel.clone();
            let recall_from_sentinel = recall_from_sentinel.clone();
            let recall_from = recall_from_sentinel as usize - 1;
            let street: usize = street_sentinel as usize-1;
            move |hand:&[u8]| -> <TraceDistribution as DistributionType>::Type{
                (recall_from..=street)
                .rev()
                .map(|st| (st, st as i32 + 1))
                .map(|(st, st_st)|{ //(street, street_sentinel)
                    let temp_hand = T::truncate_hand(street, st, hand);
                    let nriso_st = game.hand_indexify(temp_hand.as_ref(), st, st);
                    #[cfg(feature = "db_inloop")] {
                        self.query_ptl_dist_id_with_nriso(next_nriso, next_street_sentinel).unwrap()
                    } #[cfg(not(feature = "db_inloop"))] {
                        self.nriso_winning.borrow()[st].xriso_to_distribution_id.as_ref().unwrap()[nriso_st as usize]
                    }
                }).collect::<<TraceDistribution as DistributionType>::Type>()
            }
        };

        let save_to_db = Some(
            {
                let street_sentinel = street_sentinel.clone();
                let recall_from_sentinel = recall_from_sentinel.clone();
                move |priso_to_trc_dist_id/*这个东西一定是box<dyn>*/ , n|{
                    if let Err(e) = self.save_priso_to_win_trc_dist_id(priso_to_trc_dist_id, n, street_sentinel, recall_from_sentinel){
                        println!("Error:{}", e);
                    }
                }
            }
        );

        self.priso_winning_trace.borrow_mut()[street_sentinel as usize - 1][recall_from_sentinel as usize -1] =
        self.handle_partial_recall_distribution::<TraceDistribution, _, _>(street_sentinel, recall_from_sentinel, hand_to_trace, save_to_db).unwrap();

    }

    pub fn handle_street_potential_trace_distribution<'a>(&'a self, street_sentinel: i32, recall_from_sentinel: i32) // ptl trace
    {
        assert!(recall_from_sentinel >= 1);
        assert!(street_sentinel > recall_from_sentinel);

        let game : &'static T = T::instance().as_ref();

        let hand_to_trace = {
            let street_sentinel = street_sentinel.clone();
            let recall_from_sentinel = recall_from_sentinel.clone();
            let recall_from = recall_from_sentinel as usize - 1;
            let street: usize = street_sentinel as usize-1;
            move |hand:&[u8]| -> <TraceDistribution as DistributionType>::Type{
                (recall_from..=street)
                .rev()
                .map(|st| (st, st as i32 + 1))
                .map(|(st, st_st)|{ //(street, street_sentinel)
                    let temp_hand = T::truncate_hand(street, st, hand);
                    let nriso_st = game.hand_indexify(temp_hand.as_ref(), st, st);
                    #[cfg(feature = "db_inloop")] {
                        self.query_ptl_dist_id_with_nriso(next_nriso, next_street_sentinel).unwrap()
                    } #[cfg(not(feature = "db_inloop"))] {
                        if st_st == T::NUM_STREET{
                            self.nriso_winning.borrow()[st].xriso_to_distribution_id.as_ref().unwrap()[nriso_st as usize]
                        }
                        else{
                            self.nriso_potential.borrow()[st].xriso_to_distribution_id.as_ref().unwrap()[nriso_st as usize]
                        }
                    }
                }).collect::<<TraceDistribution as DistributionType>::Type>()
            }
        };

        let save_to_db = Some(
            {
                let street_sentinel = street_sentinel.clone();
                let recall_from_sentinel = recall_from_sentinel.clone();
                move |priso_to_trc_dist_id/*这个东西一定是box<dyn>*/ , n|{
                    if let Err(e) = self.save_priso_to_ptl_trc_dist_id(priso_to_trc_dist_id, n, street_sentinel, recall_from_sentinel){
                        println!("Error:{}", e);
                    }
                }
            }
        );

        

        self.priso_potential_trace.borrow_mut()[street_sentinel as usize - 1][recall_from_sentinel as usize -1] =
        self.handle_partial_recall_distribution::<TraceDistribution, _, _>(street_sentinel, recall_from_sentinel, hand_to_trace, save_to_db).unwrap();
    }
}


