use riichi::algo::agari::{self, AgariCalculator};
use riichi::algo::shanten;
use riichi::algo::sp::{InitState, SPCalculator};
use riichi::hand::hand;
use riichi::state::PlayerState;
use riichi::{t, tu8};
use std::hint::black_box;

use criterion::{criterion_group, criterion_main, Criterion};

fn shanten(c: &mut Criterion) {
    shanten::ensure_init();
    let tehai = hand("2344456m 14p 127s 2z 7p").unwrap();
    c.bench_function("shanten", |b| {
        b.iter(|| {
            let tehai = black_box(tehai);
            black_box(shanten::calc_all(&tehai, 4));
        });
    });
}

fn agari(c: &mut Criterion) {
    agari::ensure_init();
    let tehai = hand("111m 9m 9m").unwrap();
    c.bench_function("agari", |b| {
        b.iter(|| {
            let tehai = black_box(tehai);
            let calc = AgariCalculator {
                tehai: &tehai,
                is_menzen: false,
                chis: &[],
                pons: &tu8![S, C],
                minkans: &[],
                ankans: &tu8![N,],
                bakaze: tu8!(S),
                jikaze: tu8!(N),
                winning_tile: tu8!(9m),
                is_ron: true,
            };
            black_box(calc.search_yakus().unwrap());
        });
    });
}

fn sp(c: &mut Criterion) {
    let calc = SPCalculator {
        tehai_len_div3: 4,
        chis: &[],
        pons: &[],
        minkans: &[],
        ankans: &[],
        bakaze: tu8!(E),
        jikaze: tu8!(E),
        prefer_riichi: true,
        is_menzen: true,
        num_doras_in_fuuro: 0,
        dora_indicators: &[t!(6m)],
        calc_double_riichi: false,
        calc_haitei: false,
        sort_result: true,
        maximize_win_prob: true,
        calc_tegawari: true,
        calc_shanten_down: true,
    };
    let tehai = hand("3667m 23489p 34688s").unwrap();
    let mut tiles_seen = tehai;
    for ind in calc.dora_indicators {
        tiles_seen[ind.deaka().as_usize()] += 1;
    }
    let can_discard = true;
    let cur_shanten = shanten::calc_all(&tehai, calc.tehai_len_div3);
    let tsumos_left = 12;
    let init_state = InitState {
        tehai,
        akas_in_hand: [false; 3],
        tiles_seen,
        akas_seen: [false; 3],
    };
    c.bench_function(&format!("sp {cur_shanten} shanten"), |b| {
        b.iter(|| {
            let state = black_box(init_state.clone());
            let candidates = black_box(&calc)
                .calc(state, can_discard, tsumos_left, cur_shanten)
                .unwrap();
            black_box(candidates);
        });
    });

    // ---

    let calc = SPCalculator {
        tehai_len_div3: 4,
        chis: &[],
        pons: &[],
        minkans: &[],
        ankans: &[],
        bakaze: tu8!(E),
        jikaze: tu8!(E),
        prefer_riichi: true,
        is_menzen: true,
        num_doras_in_fuuro: 0,
        dora_indicators: &[t!(6m)],
        calc_double_riichi: false,
        calc_haitei: false,
        sort_result: true,
        maximize_win_prob: true,
        calc_tegawari: true,
        calc_shanten_down: true,
    };
    let tehai = hand("45677m 456778p 248s").unwrap();
    let mut tiles_seen = tehai;
    for ind in calc.dora_indicators {
        tiles_seen[ind.deaka().as_usize()] += 1;
    }
    let can_discard = true;
    let cur_shanten = shanten::calc_all(&tehai, calc.tehai_len_div3);
    let tsumos_left = 12;
    let init_state = InitState {
        tehai,
        akas_in_hand: [false; 3],
        tiles_seen,
        akas_seen: [false; 3],
    };
    c.bench_function(&format!("sp {cur_shanten} shanten"), |b| {
        b.iter(|| {
            let state = black_box(init_state.clone());
            let candidates = black_box(&calc)
                .calc(state, can_discard, tsumos_left, cur_shanten)
                .unwrap();
            black_box(candidates);
        });
    });
}

fn encode_obs(c: &mut Criterion) {
    let log = r#"
        {"type":"start_kyoku","bakaze":"S","dora_marker":"F","kyoku":1,"honba":2,"kyotaku":1,"oya":0,"scores":[32300,18000,22000,26700],"tehais":[["1m","3m","4m","5mr","6m","6m","7m","5p","8p","6s","E","W","N"],["4m","5m","5m","8m","7p","1s","3s","4s","7s","9s","E","E","N"],["1m","2m","3m","3m","7m","9m","6p","9p","1s","4s","5sr","8s","C"],["8m","8m","3p","4p","4p","5p","8p","1s","6s","9s","9s","S","F"]]}
        {"type":"tsumo","actor":0,"pai":"C"}
        {"type":"dahai","actor":0,"pai":"W","tsumogiri":false}
        {"type":"tsumo","actor":1,"pai":"N"}
        {"type":"dahai","actor":1,"pai":"8m","tsumogiri":false}
        {"type":"tsumo","actor":2,"pai":"5s"}
        {"type":"dahai","actor":2,"pai":"1s","tsumogiri":false}
        {"type":"tsumo","actor":3,"pai":"7p"}
        {"type":"dahai","actor":3,"pai":"1s","tsumogiri":false}
        {"type":"tsumo","actor":0,"pai":"7s"}
        {"type":"dahai","actor":0,"pai":"N","tsumogiri":false}
        {"type":"pon","actor":1,"target":0,"pai":"N","consumed":["N","N"]}
        {"type":"dahai","actor":1,"pai":"7p","tsumogiri":false}
        {"type":"tsumo","actor":2,"pai":"6p"}
        {"type":"dahai","actor":2,"pai":"9p","tsumogiri":false}
        {"type":"tsumo","actor":3,"pai":"2m"}
        {"type":"dahai","actor":3,"pai":"F","tsumogiri":false}
        {"type":"tsumo","actor":0,"pai":"4p"}
        {"type":"dahai","actor":0,"pai":"8p","tsumogiri":false}
        {"type":"tsumo","actor":1,"pai":"P"}
        {"type":"dahai","actor":1,"pai":"4m","tsumogiri":false}
        {"type":"tsumo","actor":2,"pai":"7s"}
        {"type":"dahai","actor":2,"pai":"5s","tsumogiri":false}
        {"type":"tsumo","actor":3,"pai":"2p"}
        {"type":"dahai","actor":3,"pai":"S","tsumogiri":false}
        {"type":"tsumo","actor":0,"pai":"2p"}
        {"type":"dahai","actor":0,"pai":"2p","tsumogiri":true}
        {"type":"tsumo","actor":1,"pai":"2s"}
        {"type":"dahai","actor":1,"pai":"5m","tsumogiri":false}
        {"type":"tsumo","actor":2,"pai":"3s"}
        {"type":"dahai","actor":2,"pai":"C","tsumogiri":false}
        {"type":"tsumo","actor":3,"pai":"6m"}
        {"type":"dahai","actor":3,"pai":"2m","tsumogiri":false}
        {"type":"tsumo","actor":0,"pai":"W"}
        {"type":"dahai","actor":0,"pai":"W","tsumogiri":true}
        {"type":"tsumo","actor":1,"pai":"3p"}
        {"type":"dahai","actor":1,"pai":"5m","tsumogiri":false}
        {"type":"tsumo","actor":2,"pai":"E"}
        {"type":"dahai","actor":2,"pai":"E","tsumogiri":true}
        {"type":"pon","actor":1,"target":2,"pai":"E","consumed":["E","E"]}
        {"type":"dahai","actor":1,"pai":"3p","tsumogiri":false}
        {"type":"tsumo","actor":2,"pai":"2p"}
        {"type":"dahai","actor":2,"pai":"2p","tsumogiri":true}
        {"type":"tsumo","actor":3,"pai":"2p"}
        {"type":"dahai","actor":3,"pai":"6s","tsumogiri":false}
        {"type":"tsumo","actor":0,"pai":"1m"}
        {"type":"dahai","actor":0,"pai":"E","tsumogiri":false}
        {"type":"tsumo","actor":1,"pai":"9p"}
        {"type":"dahai","actor":1,"pai":"9p","tsumogiri":true}
        {"type":"tsumo","actor":2,"pai":"8p"}
        {"type":"dahai","actor":2,"pai":"8p","tsumogiri":true}
        {"type":"tsumo","actor":3,"pai":"5s"}
        {"type":"dahai","actor":3,"pai":"5s","tsumogiri":true}
        {"type":"tsumo","actor":0,"pai":"3s"}
        {"type":"dahai","actor":0,"pai":"C","tsumogiri":false}
        {"type":"tsumo","actor":1,"pai":"C"}
        {"type":"dahai","actor":1,"pai":"P","tsumogiri":false}
        {"type":"tsumo","actor":2,"pai":"S"}
        {"type":"dahai","actor":2,"pai":"S","tsumogiri":true}
        {"type":"tsumo","actor":3,"pai":"3s"}
        {"type":"dahai","actor":3,"pai":"3s","tsumogiri":true}
        {"type":"tsumo","actor":0,"pai":"6p"}
        {"type":"dahai","actor":0,"pai":"3s","tsumogiri":false}
        {"type":"tsumo","actor":1,"pai":"4m"}
        {"type":"dahai","actor":1,"pai":"4m","tsumogiri":true}
        {"type":"tsumo","actor":2,"pai":"S"}
        {"type":"dahai","actor":2,"pai":"S","tsumogiri":true}
        {"type":"tsumo","actor":3,"pai":"1s"}
        {"type":"dahai","actor":3,"pai":"1s","tsumogiri":true}
        {"type":"tsumo","actor":0,"pai":"7m"}
        {"type":"dahai","actor":0,"pai":"6m","tsumogiri":false}
        {"type":"tsumo","actor":1,"pai":"W"}
        {"type":"dahai","actor":1,"pai":"W","tsumogiri":true}
        {"type":"tsumo","actor":2,"pai":"8s"}
        {"type":"dahai","actor":2,"pai":"3m","tsumogiri":false}
        {"type":"tsumo","actor":3,"pai":"1m"}
        {"type":"dahai","actor":3,"pai":"1m","tsumogiri":true}
        {"type":"tsumo","actor":0,"pai":"9m"}
        {"type":"dahai","actor":0,"pai":"9m","tsumogiri":true}
        {"type":"tsumo","actor":1,"pai":"1p"}
        {"type":"dahai","actor":1,"pai":"1p","tsumogiri":true}
        {"type":"tsumo","actor":2,"pai":"3m"}
        {"type":"dahai","actor":2,"pai":"3m","tsumogiri":true}
        {"type":"tsumo","actor":3,"pai":"2s"}
        {"type":"dahai","actor":3,"pai":"2s","tsumogiri":true}
        {"type":"tsumo","actor":0,"pai":"6s"}
        {"type":"dahai","actor":0,"pai":"7m","tsumogiri":false}
        {"type":"tsumo","actor":1,"pai":"9p"}
        {"type":"dahai","actor":1,"pai":"9p","tsumogiri":true}
        {"type":"tsumo","actor":2,"pai":"9m"}
        {"type":"dahai","actor":2,"pai":"9m","tsumogiri":true}
        {"type":"tsumo","actor":3,"pai":"P"}
        {"type":"dahai","actor":3,"pai":"P","tsumogiri":true}
        {"type":"tsumo","actor":0,"pai":"5p"}
        {"type":"dahai","actor":0,"pai":"5p","tsumogiri":true}
        {"type":"tsumo","actor":1,"pai":"2s"}
        {"type":"dahai","actor":1,"pai":"2s","tsumogiri":true}
        {"type":"tsumo","actor":2,"pai":"5s"}
        {"type":"dahai","actor":2,"pai":"7m","tsumogiri":false}
        {"type":"tsumo","actor":3,"pai":"6s"}
    "#;
    let mut ps = PlayerState::new(3);
    for line in log.trim().split('\n') {
        ps.update(&serde_json::from_str(line).unwrap()).unwrap();
    }

    c.bench_function("encode obs", |b| {
        b.iter(|| {
            let ps = black_box(&ps);
            let result = ps.encode_obs(4, false);
            black_box(result);
        });
    });
}

criterion_group!(algo, shanten, agari, sp);
criterion_group!(state, encode_obs);
criterion_main!(algo, state);
