#![allow(clippy::pedantic, clippy::nursery, clippy::cargo)]

use std::env;

use rshogi::board::position_from_sfen;
use rshogi::board::zobrist::ZobristKey;
use rshogi::board::Position;
use rshogi::types::{Move, Move32};

fn move_from_usi(pos: &Position, usi: &str) -> Option<Move32> {
    let mv16 = Move::from_usi(usi)?;
    if mv16.is_drop() {
        let piece_type = mv16.dropped_piece()?;
        Some(Move32::drop(piece_type, mv16.to_sq(), pos.turn()))
    } else {
        let from = mv16.from_sq();
        let to = mv16.to_sq();
        let piece = pos.piece_on(from);
        if mv16.is_promotion() {
            Some(Move32::promotion(from, to, piece))
        } else {
            Some(Move32::normal(from, to, piece))
        }
    }
}

fn format_key(key: ZobristKey) -> String {
    format!("{}:{}", key.high_u64(), key.low_u64())
}

fn main() {
    let mut sfen = None;
    let mut moves_arg = None;

    let mut args = env::args().skip(1);
    while let Some(arg) = args.next() {
        match arg.as_str() {
            "--sfen" => {
                sfen = args.next();
            }
            "--moves" => {
                moves_arg = args.next();
            }
            _ => {
                eprintln!("Unknown argument: {arg}");
                std::process::exit(2);
            }
        }
    }

    let sfen = sfen.unwrap_or_else(|| {
        eprintln!("--sfen is required");
        std::process::exit(2);
    });

    let mut pos = position_from_sfen(&sfen).expect("valid sfen");
    pos.init_stack();

    if let Some(moves_arg) = moves_arg {
        for token in moves_arg.split_whitespace() {
            let Some(mv) = move_from_usi(&pos, token) else {
                eprintln!("Invalid USI move: {token}");
                std::process::exit(3);
            };
            if !pos.is_legal_move32(mv) {
                eprintln!("Illegal move for position: {token}");
                std::process::exit(3);
            }
            pos.apply_move32(mv);
        }
    }

    let stack = pos.state_stack();
    let st = stack.current();

    let board_key = format_key(st.board_key);
    let hand_key = format_key(st.hand_key);
    let key = format_key(st.board_key ^ st.hand_key);

    println!("board_key={board_key} hand_key={hand_key} key={key}");
}
