#include <vector>
#include <Rcpp.h>

#include "SchachHoernchen/types.h"
#include "SchachHoernchen/utils.h"
#include "SchachHoernchen/Board.h"

//' Convert a legal FEN string to a 3D binary (integer with 0-1 entries) array
// [[Rcpp::export(rng = false)]]
Rcpp::IntegerVector fen2int(const std::vector<Board>& boards) {
    // Initialize empty chess board as a 3D binary tensor
    Rcpp::IntegerVector bitboards(8 * 8 * 12 * (int)boards.size());
    // Set dimension and dimension names (required this way since `Rcpp::Dimension`
    // does _not_ support 4D arrays)
    auto dims = Rcpp::IntegerVector({ 8, 8, 12, (int)boards.size() });
    bitboards.attr("dim") = dims;
    bitboards.attr("dimnames") = Rcpp::List::create(
        Rcpp::Named("rank")  = Rcpp::CharacterVector::create(
            "8", "7", "6", "5", "4", "3", "2", "1"
        ),
        Rcpp::Named("file")  = Rcpp::CharacterVector::create(
            "a", "b", "c", "d", "e", "f", "g", "h"
        ),
        Rcpp::Named("piece") = Rcpp::CharacterVector::create(
            "P", "N", "B", "R", "Q", "K",   // White Pieces (Upper Case)
            "p", "n", "b", "r", "q", "k"    // Black Pieces (Lower Case)
        ),
        R_NilValue
    );

    // Index to color/piece mapping (more robust)
    enum piece colorLoopup[2] = { white, black };
    enum piece pieceLookup[6] = { pawn, knight, bishop, rook, queen, king };

    // Set for every piece the corresponding pit positions, note the
    // "transposition" of the indexing from SchachHoernchen's binary indexing
    // scheme to the 3D array indexing of ranks/files.
    for (int i = 0; i < boards.size(); ++i) {
        const Board& pos = boards[i];
        for (int color = 0; color < 2; ++color) {
            for (int piece = 0; piece < 6; ++piece) {
                int slice = 6 * color + piece;
                u64 bb = pos.bb(colorLoopup[color]) & pos.bb(pieceLookup[piece]);
                for (; bb; bb &= bb - 1) {
                    // Get BitBoard index
                    int index = bitScanLS(bb);
                    // Transpose to align with printing as a Chess Board
                    index = ((index & 7) << 3) | ((index & 56) >> 3);
                    // Flip black to move positions to whites point of view
                    index ^= pos.isWhiteTurn() ? 0 : 7;
                    bitboards[768 * i + 64 * slice + index] = 1;
                }
            }
        }
    }

    return bitboards;
}
