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

use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

use rshogi::board::{self, Move32List};
use rshogi::movegen::{
    generate_legal_all_move32, generate_moves_move32, EvasionsAll, NonEvasionsAll,
};

#[derive(Debug, Clone)]
struct PositionInput {
    label: String,
    sfen: String,
}

fn load_positions(path: &PathBuf) -> Result<Vec<PositionInput>, Box<dyn std::error::Error>> {
    let file = File::open(path)?;
    let reader = BufReader::new(file);
    let mut positions = Vec::new();

    for line in reader.lines() {
        let line = line?;
        let trimmed = line.trim();
        if trimmed.is_empty() || trimmed.starts_with('#') {
            continue;
        }
        let Some((label, sfen)) = trimmed.split_once(',') else {
            continue;
        };
        let label = label.trim();
        let sfen = sfen.trim();
        if !label.is_empty() && !sfen.is_empty() {
            positions.push(PositionInput { label: label.to_string(), sfen: sfen.to_string() });
        }
    }

    Ok(positions)
}

fn parse_args() -> Result<PathBuf, Box<dyn std::error::Error>> {
    let mut positions_path: Option<PathBuf> = None;

    let mut args = env::args().skip(1);
    while let Some(arg) = args.next() {
        if arg.as_str() == "--positions" {
            let value = args.next().ok_or("--positions requires a value")?;
            positions_path = Some(PathBuf::from(value));
        }
    }

    Ok(positions_path.unwrap_or_else(|| PathBuf::from("data/bench/diverse_positions.csv")))
}

fn moves_to_usi(list: &Move32List) -> String {
    let mut out = String::new();
    for (i, mv) in list.iter().enumerate() {
        if i > 0 {
            out.push(' ');
        }
        out.push_str(&mv.to_usi());
    }
    out
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let positions_path = parse_args()?;
    let positions = load_positions(&positions_path)?;
    if positions.is_empty() {
        return Err("no positions loaded from CSV".into());
    }

    println!("engine,rshogi");
    println!("label,in_check,pseudo_count,pseudo_moves,legal_count,legal_moves");

    for pos in positions {
        let position =
            board::position_from_sfen(&pos.sfen).map_err(|e| format!("invalid sfen: {e}"))?;
        let in_check = !position.checkers().is_empty();

        let mut pseudo = Move32List::new();
        if in_check {
            generate_moves_move32::<EvasionsAll>(&position, &mut pseudo);
        } else {
            generate_moves_move32::<NonEvasionsAll>(&position, &mut pseudo);
        }

        let mut legal = Move32List::new();
        generate_legal_all_move32(&position, &mut legal);

        println!(
            "{},{},{},{},{},{}",
            pos.label,
            if in_check { 1 } else { 0 },
            pseudo.len(),
            moves_to_usi(&pseudo),
            legal.len(),
            moves_to_usi(&legal)
        );
    }

    Ok(())
}
