mod date;
pub use date::Date;

pub mod go;

mod tree;
use tree::parse_collection;

use thiserror::Error;

#[derive(Debug)]
pub enum Error {
    InvalidField,
    InvalidBoardSize,
    Incomplete,
    InvalidSgf(VerboseNomError),
}

#[derive(Debug)]
pub struct VerboseNomError(nom::error::VerboseError<String>);

impl From<nom::error::VerboseError<&str>> for VerboseNomError {
    fn from(err: nom::error::VerboseError<&str>) -> Self {
        VerboseNomError(nom::error::VerboseError {
            errors: err
                .errors
                .into_iter()
                .map(|err| (err.0.to_owned(), err.1))
                .collect(),
        })
    }
}

impl From<nom::Err<nom::error::VerboseError<&str>>> for Error {
    fn from(err: nom::Err<nom::error::VerboseError<&str>>) -> Self {
        match err {
            nom::Err::Incomplete(_) => Error::Incomplete,
            nom::Err::Error(e) => Error::InvalidSgf(VerboseNomError::from(e)),
            nom::Err::Failure(e) => Error::InvalidSgf(VerboseNomError::from(e)),
        }
    }
}

#[derive(Debug, PartialEq, Error)]
pub enum ParseError {
    #[error("An unknown error was found")]
    NomError(nom::error::Error<String>),
}

impl From<nom::error::Error<&str>> for ParseError {
    fn from(err: nom::error::Error<&str>) -> Self {
        Self::NomError(nom::error::Error {
            input: err.input.to_owned(),
            code: err.code.clone(),
        })
    }
}

pub enum Game {
    Go(go::Game),
    Unsupported(tree::Tree),
}

pub fn parse_sgf(input: &str) -> Result<Vec<Game>, Error> {
    let (_, trees) = parse_collection::<nom::error::VerboseError<&str>>(input)?;
    Ok(trees
        .into_iter()
        .map(|t| match t.sequence[0].find_prop("GM") {
            Some(prop) if prop.values == vec!["1".to_owned()] => {
                Game::Go(go::Game::try_from(t).expect("properly structured game tree"))
            }
            _ => Game::Unsupported(t),
        })
        .collect::<Vec<Game>>())
}

/*
impl From<(&str, VerboseErrorKind)> for

impl From<nom::error::VerboseError<&str>> for ParseError {
    fn from(err: nom::error::VerboseError<&str>) -> Self {
        Self::NomErrors(
            err.errors
                .into_iter()
                .map(|err| ParseError::from(err))
                .collect(),
        )
        /*
        Self::NomError(nom::error::Error {
            input: err.input.to_owned(),
            code: err.code.clone(),
        })
        */
    }
}
*/
