use crate::combine::expected::Expected;
use crate::combine::parser::{Node, Parser};
use crate::combine::result::{PResultExt, ParseResult};
use crate::lexer::Lexer;
use crate::lexer::span::Spanned;
use crate::lexer::token::{Keyword, Token};

#[derive(Debug, Clone)]
pub enum Either<L, R> {
    Left(L),
    Right(R),
}

#[macro_export]
macro_rules! match_either {

    // terminal case: BOTH sides explicitly matched
    ($expr:expr,
        $left_pat:pat => $left_body:expr,
        $right_pat:pat => $right_body:expr $(,)?
    ) => {{
        match $expr {
            Either::Left($left_pat) => $left_body,
            Either::Right($right_pat) => $right_body,
        }
    }};

    // recursive case: still nested Either
    ($expr:expr,
        $l_pat:pat => $l_body:expr,
        $($rest:tt)+
    ) => {{
        match $expr {
            Either::Left($l_pat) => {
                $l_body
            }
            Either::Right(next) => match_either!(next, $($rest)+),
        }
    }};
}

impl<L: Node, R: Node> Node for Either<L, R> {}

#[derive(Debug, Clone)]
pub struct Choice<K: Keyword, L: Parser<K>, R: Parser<K>> {
    lhs: L,
    rhs: R,
    expected: Expected<K>,
    phatom: std::marker::PhantomData<K>,
}

impl<K: Keyword, L: Parser<K>, R: Parser<K>> Choice<K, L, R> {
    pub fn new(lhs: L, rhs: R) -> Self {
        let expected = lhs.expected().clone().or(rhs.expected().clone());
        Self {
            lhs,
            rhs,
            expected,
            phatom: std::marker::PhantomData,
        }
    }
}

#[macro_export]
macro_rules! any {
    ($last:expr $(,)? ) => {
        $last.clone()
    };
    ($first:expr $(, $rest:expr)+ $(,)? ) => {
        $crate::combine::impls::choice::Choice::new($first.clone(), $crate::any!($($rest),*))
    };

    ($last:expr; |$pat:pat_param| $body:expr) => {
        $crate::map!($last.clone(), |$pat| $body)
    };
    ($first:expr $(, $rest:expr)+ ; |$pat:pat_param| $body:expr) => {
        $crate::map!(any!($first.clone(), $($rest),*), |$pat| $body)
    };
}

impl<K: Keyword, L: Parser<K>, R: Parser<K>> Parser<K> for Choice<K, L, R> {
    type Item = Either<L::Item, R::Item>;

    fn parse<'lex, M: Fn(&mut Lexer<'lex, K>) -> bool>(
        &self,
        lexer: &mut Lexer<'lex, K>,
        abort: M,
    ) -> ParseResult<Self::Item> {
        /*
         */

        if self.lhs.can_parse(&lexer.peek()) {
            self.lhs.parse(lexer, abort).map_item(Either::Left)
        } else if self.rhs.can_parse(&lexer.peek()) {
            self.rhs.parse(lexer, abort).map_item(Either::Right)
        } else {
            let peek = lexer.peek();
            let expected = self.expected();
            let span = peek.span();
            Err(rail_diag::report!()
                .message(expected.format(peek.kind().tag(), true))
                .annotate(span, |_| {
                    //builder.message(format!("found {}", lexer.peek().kind()));
                })
                .build())
        }
    }

    fn can_parse(&self, peek: &Token<K>) -> bool {
        self.lhs.can_parse(peek) || self.rhs.can_parse(peek)
    }

    fn expected(&self) -> &Expected<K> {
        &self.expected
    }

    fn is_optional() -> bool {
        L::is_optional() && R::is_optional()
    }

    fn is_trivially_skippable() -> bool {
        L::is_trivially_skippable() || R::is_trivially_skippable()
    }
}
