Documentation
use super::{parameters, token::Token, Action, Expression, Result};
use logos::{Lexer, Logos};

fn parse_name<'a>(lexer: &mut Lexer<'a, Token<'a>>) -> Result<&'a str> {
    match lexer.next() {
        Some(token) => match token {
            Ok(Token::Name(name)) => Ok(name),
            Ok(_) => return Err(("unexpected token", lexer.span())),
            Err(_) => return Err(("invalid token", lexer.span())),
        },
        None => return Err(("erroneous action", lexer.span())),
    }
}

fn parse_expression<'a>(
    lexer: &mut Lexer<'a, Token<'a>>,
) -> Result<Expression<'a>> {
    let token = lexer
        .next()
        .ok_or(("unexpected end of input", lexer.span()))?;
    match token {
        Ok(Token::Name(name)) => {
            let mut parameters = Vec::new();

            while let Some(token) = lexer.next() {
                match token {
                    Ok(Token::Name(name)) => parameters.push(name),
                    Ok(Token::RParen) => break,
                    _ => return Err(("unexpected token", lexer.span())),
                }
            }

            return Ok(Expression::Fact {
                predicate: name,
                parameters,
            });
        }
        Ok(Token::Not) => {
            let n_token = lexer
                .next()
                .ok_or(("unexpected end of input", lexer.span()))?;
            let expression = match n_token {
                Ok(Token::LParen) => parse_expression(lexer),
                _ => return Err(("unexpected token", lexer.span())),
            }?;
            match lexer.next() {
                Some(token) => match token {
                    Ok(Token::RParen) => {}
                    Ok(_) => return Err(("unexpected token", lexer.span())),
                    Err(_) => return Err(("invalid token", lexer.span())),
                },
                None => return Err(("unexpected end of input", lexer.span())),
            }
            return Ok(Expression::Not(Box::new(expression)));
        }
        Ok(Token::And) => {
            let mut expressions = Vec::new();

            while let Some(token) = lexer.next() {
                match token {
                    Ok(Token::RParen) => {
                        return Ok(Expression::And(expressions))
                    }
                    Ok(Token::LParen) => {
                        expressions.push(parse_expression(lexer)?)
                    }
                    _ => return Err(("unexpected token", lexer.span())),
                }
            }

            return Err(("unexpected end of input", lexer.span()));
        }
        Ok(Token::Or) => {
            let mut expressions = Vec::new();

            while let Some(token) = lexer.next() {
                match token {
                    Ok(Token::RParen) => {
                        return Ok(Expression::Or(expressions))
                    }
                    Ok(Token::LParen) => {
                        expressions.push(parse_expression(lexer)?)
                    }
                    _ => return Err(("unexpected token", lexer.span())),
                }
            }

            return Err(("unexpected end of input", lexer.span()));
        }
        _ => return Err(("unexpected token", lexer.span())),
    }
}

fn parse_expression_root<'a>(
    lexer: &mut Lexer<'a, Token<'a>>,
) -> Result<Expression<'a>> {
    match lexer.next() {
        Some(token) => match token {
            Ok(Token::LParen) => parse_expression(lexer),
            Ok(_) => return Err(("unexpected token", lexer.span())),
            Err(_) => return Err(("invalid token", lexer.span())),
        },
        None => return Err(("unexpected end of input", lexer.span())),
    }
}

pub(super) fn parse_stream<'a>(
    lexer: &mut Lexer<'a, Token<'a>>,
) -> Result<Action<'a>> {
    let name = parse_name(lexer)?;
    let mut parameters = None;
    let mut precondition = None;
    let mut effect = None;

    while let Some(token) = lexer.next() {
        match token {
            Ok(Token::Parameters) => match lexer.next() {
                Some(token) => match token {
                    Ok(Token::LParen) => {
                        parameters = Some(parameters::parse(lexer)?)
                    }
                    Ok(_) => return Err(("unexpected token", lexer.span())),
                    Err(_) => return Err(("invalid token", lexer.span())),
                },
                None => return Err(("unexpected end of input", lexer.span())),
            },
            Ok(Token::Precondition) => {
                precondition = Some(parse_expression_root(lexer)?)
            }
            Ok(Token::Effect) => effect = Some(parse_expression_root(lexer)?),
            Ok(Token::LParen) => continue,
            Ok(Token::RParen) => break,
            Ok(_) => return Err(("unexpected token", lexer.span())),
            Err(_) => return Err(("invalid token", lexer.span())),
        }
    }

    let effect = match effect {
        Some(effect) => effect,
        None => return Err(("action missing effect", lexer.span())),
    };

    Ok(Action {
        name,
        parameters,
        precondition,
        effect,
    })
}

pub fn parse<'a>(input: &'a str) -> Result<Action<'a>> {
    let mut lexer = Token::lexer(input);
    match lexer.next() {
        Some(token) => match token {
            Ok(Token::LParen) => {}
            Ok(_) => return Err(("unexpected token", lexer.span())),
            Err(_) => return Err(("invalid token", lexer.span())),
        },
        None => return Err(("unexpected end of input", lexer.span())),
    };
    match lexer.next() {
        Some(token) => match token {
            Ok(Token::Action) => {}
            Ok(_) => return Err(("unexpected token", lexer.span())),
            Err(_) => return Err(("invalid token", lexer.span())),
        },
        None => return Err(("unexpected end of input", lexer.span())),
    };
    parse_stream(&mut lexer)
}