use super::lexer::Token;
use crate::model::{
    AssignmentOperator, BinaryOperator, Block, Call, CompilerError, ConstExpr,
    Declaration, Dependency, Expression, Number, Program, Statement, TypeId,
    UnaryOperator, Variable,
};
use crate::{expect_tt, expect_value};
use std::ops::{ControlFlow, FromResidual, Try};

#[derive(Debug, Clone)]
pub enum ParseResult<T, E> {
    Accept(T),
    Deny,
    Reject(E),
}

pub struct Parser {
    tokens: Vec<Token>,
    idx: usize,
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        Self { tokens, idx: 0 }
    }

    pub fn parse(&mut self) -> ParseResult<Program, CompilerError> {
        let mut declarations = Vec::new();

        while let ParseResult::Accept(_) = self.peek_next() {
            declarations.push(self.parse_declaration()?);
        }

        ParseResult::Accept(Program { declarations })
    }

    fn parse_declaration(&mut self) -> ParseResult<Declaration, CompilerError> {
        if expect_tt!(self.peek_next()?, Fn).accepted() {
            return self.parse_func();
        }

        if expect_tt!(self.peek_next()?, Struct).accepted() {
            return self.parse_struct();
        }

        if expect_tt!(self.peek_next()?, Include).accepted() {
            // expect include keyword
            let _ = self.next();

            // expect namespace identifier
            let name = expect_value!(self.next()?, Identifier)?;

            // expect colon
            let _ = expect_tt!(self.next()?, Colon)?;

            // expect string literal (module path)
            let path = expect_value!(self.next()?, String)?;

            // expect semicolon
            let _ = expect_tt!(self.next()?, Semicolon)?;

            return ParseResult::Accept(Declaration::Dependency(Dependency {
                name: name.name,
                path,
            }));
        }

        if expect_tt!(self.peek_next()?, Const, Static).accepted() {
            let is_const = match self.next()? {
                Token::Const => true,
                Token::Static => false,
                _ => {
                    return ParseResult::Reject(CompilerError::Generic(String::from(
                        "This can't happen!",
                    )));
                }
            };

            let var = self.parse_var_decl()?;

            let _ = expect_tt!(self.next()?, Assign)?;

            let value = self.next()?;
            let init = match value {
                Token::String(x) => Some(ConstExpr::String(x)),
                Token::SignedInt(x, _) => Some(ConstExpr::Number(x)),
                Token::UnsignedInt(x, _) => Some(ConstExpr::Number(x as i32)),
                _ => {
                    return ParseResult::Reject(CompilerError::UnexpectedToken(
                        value.tt().to_string(),
                    ));
                }
            };

            let _ = expect_tt!(self.next()?, Semicolon)?;

            return ParseResult::Accept(Declaration::Variable {
                var,
                init,
                is_const,
            });
        }

        ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
    }

    fn parse_struct(&mut self) -> ParseResult<Declaration, CompilerError> {
        let _ = expect_tt!(self.next()?, Struct)?;
        let name = expect_value!(self.next()?, Identifier)?;

        let _ = expect_tt!(self.next()?, LeftBrace)?;

        let mut fields = Vec::new();
        while expect_tt!(self.peek_next()?, Identifier).accepted() {
            let arg = self.parse_var_decl()?;
            fields.push(arg);

            if expect_tt!(self.peek_next()?, Comma).accepted() {
                self.next()?;
            } else {
                break;
            }
        }

        let _ = expect_tt!(self.next()?, RightBrace)?;
        ParseResult::Accept(Declaration::Struct { name, fields })
    }

    fn parse_func(&mut self) -> ParseResult<Declaration, CompilerError> {
        // expect function keyword
        let _ = expect_tt!(self.next()?, Fn);
        // expect function name
        let name = expect_value!(self.next()?, Identifier)?;

        // expect left paren
        let _ = expect_tt!(self.next()?, LeftParen)?;

        let mut params = Vec::new();
        while expect_tt!(self.peek_next()?, Identifier).accepted() {
            let arg = self.parse_var_decl()?;
            params.push(arg);

            if expect_tt!(self.peek_next()?, Comma).accepted() {
                self.next()?;
            } else {
                break;
            }
        }

        // expect right paren
        let _ = expect_tt!(self.next()?, RightParen)?;

        // see if we can parse the return type!
        let mut return_type = TypeId::Void;
        if expect_tt!(self.peek_next()?, RightArrow).accepted() {
            let _ = self.next();
            return_type = self.parse_type()?;
        }

        // expect vald block
        if expect_tt!(self.peek_next()?, LeftBrace).accepted() {
            ParseResult::Accept(Declaration::Function {
                name: name.name,
                params,
                return_type,
                body: self.parse_block()?,
            })
        } else {
            ParseResult::Reject(CompilerError::UnexpectedToken(
                self.peek_next()?.tt().to_string(),
            ))
        }
    }

    fn parse_block(&mut self) -> ParseResult<Block, CompilerError> {
        // expect left brace
        let _ = expect_tt!(self.next()?, LeftBrace)?;

        let mut block = Vec::new();
        while !expect_tt!(self.peek_next()?, RightBrace).accepted() {
            block.push(self.parse_statement()?);
        }

        // expect right brace
        let _ = expect_tt!(self.next()?, RightBrace)?;

        ParseResult::Accept(block)
    }

    fn parse_statement(&mut self) -> ParseResult<Statement, CompilerError> {
        // handle if statements
        if expect_tt!(self.peek_next()?, If).accepted() {
            self.next()?;

            let condition = self.parse_expression()?;

            let then_stmt = self.parse_block()?;

            if !expect_tt!(self.peek_next()?, Else).accepted() {
                return ParseResult::Accept(Statement::If {
                    condition,
                    then_stmt,
                    else_stmt: vec![],
                });
            }

            let _ = expect_tt!(self.next()?, Else)?;

            let else_stmt = self.parse_block()?;

            return ParseResult::Accept(Statement::If {
                condition,
                then_stmt,
                else_stmt,
            });
        }

        // handle while loops
        if expect_tt!(self.peek_next()?, While).accepted() {
            self.next()?;

            // expect valid expression
            let expr = self.parse_expression()?;

            // expect valid block after
            let block = self.parse_block()?;

            // return result
            return ParseResult::Accept(Statement::While {
                condition: expr,
                body: block,
            });
        }

        // handle indefinite loops
        if expect_tt!(self.peek_next()?, Loop).accepted() {
            self.next()?;

            // parse the inner block
            return ParseResult::Accept(Statement::Loop(self.parse_block()?));
        }

        if expect_tt!(self.peek_next()?, Return).accepted() {
            self.next()?;

            // handle case where nothing is returned
            if expect_tt!(self.peek_next()?, Semicolon).accepted() {
                return ParseResult::Accept(Statement::Return(None));
            }

            let expr = self.parse_expression()?;
            expect_tt!(self.next()?, Semicolon)?;

            return ParseResult::Accept(Statement::Return(Some(expr)));
        }

        if expect_tt!(self.peek_next()?, Break).accepted() {
            self.next()?;

            // expect semicolon
            expect_tt!(self.next()?, Semicolon)?;

            // return result
            return ParseResult::Accept(Statement::Break);
        }

        if expect_tt!(self.peek_next()?, Continue).accepted() {
            self.next()?;

            // expect semicolon
            expect_tt!(self.next()?, Semicolon)?;

            // return result
            return ParseResult::Accept(Statement::Continue);
        }

        // handle writes to pointers!
        if expect_tt!(self.peek_next()?, Star).accepted() {
            self.next()?;

            let left = if expect_tt!(self.peek_next()?, Identifier).accepted() {
                let identifier = expect_value!(self.next()?, Identifier)?;

                Expression::Variable {
                    name: identifier,
                    expr_type: None,
                }
            } else if expect_tt!(self.peek_next()?, LeftParen).accepted() {
                self.next()?;

                let expr = self.parse_expression()?;

                let _ = expect_tt!(self.next()?, RightParen).accepted();

                expr
            } else {
                return ParseResult::Reject(CompilerError::UnexpectedToken(
                    self.peek_next()?.tt().to_string(),
                ));
            };

            let _ = expect_tt!(self.next()?, Assign)?;

            let right = self.parse_expression()?;

            // expect semicolon
            expect_tt!(self.next()?, Semicolon)?;

            // return result
            return ParseResult::Accept(Statement::PtrWrite {
                ptr: left,
                value: right,
            });
        }

        // handle let statements (declarations)
        if expect_tt!(self.peek_next()?, Let).accepted() {
            self.next();

            // expect variable name and type.
            let name = self.parse_var_decl()?;

            // handle uninitialised variable case
            if expect_tt!(self.peek_next()?, Semicolon).accepted() {
                self.next();
                return ParseResult::Accept(Statement::Declaration {
                    var: name,
                    value: None,
                });
            }

            // handle initialised case
            // expect equals
            let _ = expect_tt!(self.next()?, Assign)?;

            // expect a valid expression
            let expr = self.parse_expression()?;

            let _ = expect_tt!(self.next()?, Semicolon);

            // return statement
            return ParseResult::Accept(Statement::Declaration {
                var: name,
                value: Some(expr),
            });
        }

        // handle an in-place function call
        if let ParseResult::Accept(name) = expect_value!(self.peek_next()?, Identifier)
            && let ParseResult::Accept(operator) = expect_tt!(
                self.peek(1)?,
                Assign,
                PlusEqual,
                MinusEqual,
                StarEqual,
                SlashEqual,
                PercentEqual,
                AndEqual,
                OrEqual,
                XorEqual,
                ShlEqual,
                ShrEqual
            )
        {
            // consume name token
            self.next()?;

            // pattern match to find operator
            let operator = match operator {
                Token::Assign => AssignmentOperator::Assign,
                Token::PlusEqual => AssignmentOperator::AddAssign,
                Token::MinusEqual => AssignmentOperator::SubAssign,
                Token::StarEqual => AssignmentOperator::MulAssign,
                Token::SlashEqual => AssignmentOperator::DivAssign,
                Token::PercentEqual => AssignmentOperator::ModAssign,
                Token::AndEqual => AssignmentOperator::AndAssign,
                Token::OrEqual => AssignmentOperator::OrAssign,
                Token::XorEqual => AssignmentOperator::XorAssign,
                Token::ShlEqual => AssignmentOperator::LeftShiftAssign,
                Token::ShrEqual => AssignmentOperator::RightShiftAssign,
                _ => {
                    return ParseResult::Reject(CompilerError::UnexpectedToken(
                        self.peek_next()?.tt().to_string(),
                    ));
                }
            };

            // consume operator token
            self.next()?;

            let value = self.parse_expression()?;

            let _ = expect_tt!(self.next()?, Semicolon);

            return ParseResult::Accept(Statement::Assign {
                varname: name.name,
                operator,
                value,
            });
        }

        // parse an expression and a semicolon
        let expr = self.parse_expression()?;
        let _ = expect_tt!(self.next()?, Semicolon)?;

        ParseResult::Accept(Statement::Expression { expr })
    }

    fn parse_expression(&mut self) -> ParseResult<Expression, CompilerError> {
        self.parse_logical_or()
    }

    fn parse_logical_or(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_logical_and()?;

        let op = match self.peek_next()? {
            Token::LogicalOr => BinaryOperator::LogicalOr,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_logical_or()?),
            type_id: Some(TypeId::U32),
        })
    }

    fn parse_logical_and(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_bitwise_or()?;

        let op = match self.peek_next()? {
            Token::LogicalAnd => BinaryOperator::LogicalAnd,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_logical_and()?),
            type_id: Some(TypeId::U32),
        })
    }

    fn parse_bitwise_or(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_bitwise_xor()?;

        let op = match self.peek_next()? {
            Token::Pipe => BinaryOperator::BitwiseOr,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_bitwise_or()?),
            type_id: Some(TypeId::U32),
        })
    }

    fn parse_bitwise_xor(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_bitwise_and()?;

        let op = match self.peek_next()? {
            Token::Caret => BinaryOperator::BitwiseXor,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_bitwise_xor()?),
            type_id: Some(TypeId::U32),
        })
    }

    fn parse_bitwise_and(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_comparison()?;

        let op = match self.peek_next()? {
            Token::Ampersand => BinaryOperator::BitwiseAnd,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_bitwise_and()?),
            type_id: Some(TypeId::U32),
        })
    }

    fn parse_comparison(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_shift()?;

        let op = match self.peek_next()? {
            Token::EqualEqual => BinaryOperator::Equal,
            Token::BangEqual => BinaryOperator::NotEqual,
            Token::Less => BinaryOperator::LessThan,
            Token::Greater => BinaryOperator::GreaterThan,
            Token::LessEqual => BinaryOperator::LessOrEqual,
            Token::GreaterEqual => BinaryOperator::GreaterOrEqual,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_comparison()?),
            type_id: Some(TypeId::Bool),
        })
    }

    fn parse_shift(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_additive()?;

        let op = match self.peek_next()? {
            Token::LeftShift => BinaryOperator::LeftShift,
            Token::RightShift => BinaryOperator::RightShift,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_shift()?),
            type_id: Some(TypeId::U32),
        })
    }

    fn parse_additive(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_multiplicative()?;

        let op = match self.peek_next()? {
            Token::Plus => BinaryOperator::Add,
            Token::Minus => BinaryOperator::Sub,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_additive()?),
            type_id: Some(TypeId::U32),
        })
    }

    fn parse_multiplicative(&mut self) -> ParseResult<Expression, CompilerError> {
        let left = self.parse_unary()?;

        let op = match self.peek_next()? {
            Token::Star => BinaryOperator::Mul,
            Token::Slash => BinaryOperator::Div,
            _ => return ParseResult::Accept(left),
        };

        self.next()?;
        ParseResult::Accept(Expression::Binary {
            op,
            left: Box::new(left),
            right: Box::new(self.parse_multiplicative()?),
            type_id: None,
        })
    }

    fn parse_unary(&mut self) -> ParseResult<Expression, CompilerError> {
        let op = match self.peek_next()? {
            // prefix inc/dec
            Token::PlusPlus => UnaryOperator::Increment,
            Token::MinusMinus => UnaryOperator::Decrement,

            // arithmetic
            Token::Plus => UnaryOperator::Plus,
            Token::Minus => UnaryOperator::Minus,

            // pointer
            Token::Star => UnaryOperator::Dereference,
            Token::Ampersand => UnaryOperator::AddressOf,

            // boolean
            Token::Bang => UnaryOperator::LogicalNot,
            Token::Tilde => UnaryOperator::BitwiseNot,

            Token::SizeOf => UnaryOperator::SizeOf,
            _ => {
                let expr = self.parse_primary()?;
                return self.parse_postfix(expr);
            }
        };

        self.next()?;
        let operand = Box::new(self.parse_unary()?);
        ParseResult::Accept(Expression::Unary {
            op,
            operand,
            type_id: None,
        })
    }

    fn parse_postfix(
        &mut self,
        mut expr: Expression,
    ) -> ParseResult<Expression, CompilerError> {
        loop {
            match self.peek_next()? {
                // Type cast: expr as Type
                Token::As => {
                    self.next()?; // consume 'as'
                    let target_type = self.parse_type()?;
                    expr = Expression::TypeCast {
                        expr: Box::new(expr),
                        target_type,
                        type_id: None,
                    };
                }

                // Postfix increment/decrement
                Token::PlusPlus => {
                    self.next()?;
                    expr = Expression::UnaryPostfix {
                        op: UnaryOperator::Increment,
                        operand: Box::new(expr),
                        type_id: None,
                    };
                }
                Token::MinusMinus => {
                    self.next()?;
                    expr = Expression::UnaryPostfix {
                        op: UnaryOperator::Decrement,
                        operand: Box::new(expr),
                        type_id: None,
                    };
                }

                // Array indexing: expr[index]
                Token::LeftBracket => {
                    self.next()?; // consume '['
                    let index = Box::new(self.parse_expression()?);

                    let _ = expect_tt!(self.next()?, RightBracket)?;

                    expr = Expression::IndexAccess {
                        expr: Box::new(expr),
                        index,
                        type_id: None,
                    };
                }

                // Function call: expr(args...)
                Token::LeftParen => {
                    self.next()?; // consume '('
                    let mut args = Vec::new();

                    if !matches!(self.peek_next()?, Token::RightParen) {
                        loop {
                            args.push(self.parse_expression()?);
                            if !matches!(self.peek_next()?, Token::Comma) {
                                break;
                            }
                            self.next()?; // consume comma
                        }
                    }

                    let _ = expect_tt!(self.next()?, RightParen)?;

                    if let Expression::Variable { name, .. } = expr {
                        expr = Expression::Call {
                            func: Call { name, args },
                            type_id: None,
                        };
                    }
                }

                // Member access: expr.member (if you support structs)
                Token::Dot => {
                    self.next()?;
                    let field_name = expect_value!(self.next()?, Identifier)?;
                    expr = Expression::MemberAccess {
                        expr: Box::new(expr),
                        field_name,
                        type_id: None,
                    };
                }

                // No more postfix operations
                _ => break,
            }
        }

        ParseResult::Accept(expr)
    }

    fn parse_primary(&mut self) -> ParseResult<Expression, CompilerError> {
        match self.peek_next()? {
            Token::UnsignedInt(value, type_id) => {
                self.next()?;
                ParseResult::Accept(Expression::Number(Number::Unsigned(value, type_id)))
            }
            Token::SignedInt(value, type_id) => {
                self.next()?;
                ParseResult::Accept(Expression::Number(Number::Signed(value, type_id)))
            }
            Token::String(value) => {
                self.next()?;
                ParseResult::Accept(Expression::StringLiteral(value))
            }
            Token::Char(value) => {
                self.next()?;
                ParseResult::Accept(Expression::CharLiteral(value))
            }

            Token::Identifier(name) => {
                self.next()?;

                // if the next token isn't the beginning of a struct literal this is just
                // an identifier.
                // if !expect_tt!(self.peek_next()?, LeftBrace).accepted() {
                //     return ParseResult::Accept(Expression::Variable {
                //         name,
                //         expr_type: None,
                //     });
                // }
                //
                ParseResult::Accept(Expression::Variable {
                    name,
                    expr_type: None,
                })

                // let _ = self.next()?;

                // let mut fields = Vec::new();
                // while !expect_tt!(self.peek_next()?, RightBrace).accepted() {
                //     let name = expect_value!(self.next()?, Identifier)?;
                //     let _ = expect_tt!(self.next()?, Colon)?;
                //     let expr = self.parse_expression()?;

                //     fields.push((name, expr));

                //     if expect_tt!(self.peek_next()?, Comma).accepted() {
                //         self.next()?;
                //     } else {
                //         break;
                //     }
                // }

                // let _ = expect_tt!(self.next()?, RightBrace)?;

                // ParseResult::Accept(Expression::StructLiteral {
                //     name,
                //     fields,
                //     type_id: None,
                // })
            }
            Token::LeftBracket => {
                self.next()?; // consume '['
                let mut elements = Vec::new();

                if !matches!(self.peek_next()?, Token::RightBracket) {
                    loop {
                        elements.push(self.parse_expression()?);
                        if !matches!(self.peek_next()?, Token::Comma) {
                            break;
                        }
                        self.next()?; // consume comma
                    }
                }

                expect_tt!(self.next()?, RightBracket)?;
                ParseResult::Accept(Expression::ArrayLiteral {
                    elements,
                    type_id: None,
                })
            }
            Token::LeftParen => {
                self.next()?;
                let expr = self.parse_expression()?;
                let _ = expect_tt!(self.next()?, RightParen)?;
                ParseResult::Accept(expr)
            }
            _ => ParseResult::Reject(CompilerError::UnexpectedToken(
                self.peek_next()?.tt().to_string(),
            )),
        }
    }

    fn parse_var_decl(&mut self) -> ParseResult<Variable, CompilerError> {
        let name = expect_value!(self.next()?, Identifier)?;

        let _ = expect_tt!(self.next()?, Colon)?;

        let type_id = self.parse_type()?;

        ParseResult::Accept(Variable {
            name: name.name,
            type_id,
        })
    }

    fn parse_type(&mut self) -> ParseResult<TypeId, CompilerError> {
        // parse primitive or named type
        if expect_tt!(self.peek_next()?, Identifier).accepted() {
            return self.parse_type_identifier();
        }

        // parse array type
        if expect_tt!(self.peek_next()?, LeftBracket).accepted() {
            let _ = self.next()?;

            let internal_type = self.parse_type()?;
            let _ = expect_tt!(self.next()?, Semicolon)?;

            let size = expect_value!(self.next()?, UnsignedInt)?;

            let _ = expect_tt!(self.next()?, RightBracket)?;

            return ParseResult::Accept(TypeId::Array {
                r#type: Box::new(internal_type),
                size: size as usize,
            });
        }

        // parse tuple type
        if expect_tt!(self.peek_next()?, LeftParen).accepted() {
            let _ = self.next()?;

            let mut types = Vec::new();
            while !expect_tt!(self.peek_next()?, RightParen).accepted() {
                types.push(self.parse_type()?);
                if !expect_tt!(self.peek_next()?, Comma).accepted() {
                    break;
                }
                let _ = self.next()?;
            }
            let _ = expect_tt!(self.next()?, RightParen)?;

            return ParseResult::Accept(TypeId::Tuple(types));
        }

        ParseResult::Reject(CompilerError::Generic(format!(
            "Parsing type but no valid type was detected: {:?}",
            self.peek_next()?
        )))
    }

    fn parse_type_identifier(&mut self) -> ParseResult<TypeId, CompilerError> {
        // get the type name incl namespace
        let name = expect_value!(self.next()?, Identifier)?;

        let type_id = match name.name.as_str() {
            "u32" => TypeId::U32,
            "u16" => TypeId::U16,
            "u8" => TypeId::U8,
            "i32" => TypeId::I32,
            "i16" => TypeId::I16,
            "i8" => TypeId::I8,
            "void" => TypeId::Void,
            "char" => TypeId::Char,
            "str" => TypeId::Ptr(Box::new(TypeId::Char)),
            _ => {
                let mut generics = Vec::new();
                if expect_tt!(self.peek_next()?, Less).accepted() {
                    let _ = self.next()?;

                    // loop until we find the closing '>'
                    while !expect_tt!(self.peek_next()?, Greater).accepted() {
                        generics.push(self.parse_type()?);
                        if !expect_tt!(self.peek_next()?, Comma).accepted() {
                            break;
                        }
                        let _ = self.next()?;
                    }
                    let _ = expect_tt!(self.next()?, Greater)?;
                }

                TypeId::UnknownCustom { name, generics }
            }
        };

        ParseResult::Accept(type_id)
    }

    fn next(&mut self) -> ParseResult<Token, CompilerError> {
        if self.idx >= self.tokens.len() {
            ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
        } else {
            let token = self.tokens[self.idx].clone();
            self.idx += 1;
            ParseResult::Accept(token)
        }
    }

    fn peek_next(&self) -> ParseResult<Token, CompilerError> {
        if self.idx >= self.tokens.len() {
            ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
        } else {
            ParseResult::Accept(self.tokens[self.idx].clone())
        }
    }

    fn peek(&self, offset: usize) -> ParseResult<Token, CompilerError> {
        if self.idx + offset >= self.tokens.len() {
            ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
        } else {
            ParseResult::Accept(self.tokens[self.idx + offset].clone())
        }
    }
}

impl<T, E> ParseResult<T, E> {
    pub fn accepted(&self) -> bool {
        matches!(self, ParseResult::Accept(_))
    }
}

pub enum ParseResultResidual<T> {
    Deny,
    Reject(T),
}

impl<T, E> Try for ParseResult<T, E> {
    type Output = T;
    type Residual = ParseResultResidual<E>;

    fn from_output(output: T) -> Self {
        ParseResult::Accept(output)
    }

    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ParseResult::Accept(v) => ControlFlow::Continue(v),
            ParseResult::Deny => ControlFlow::Break(ParseResultResidual::Deny),
            ParseResult::Reject(e) => ControlFlow::Break(ParseResultResidual::Reject(e)),
        }
    }
}

impl<T, E> FromResidual for ParseResult<T, E> {
    fn from_residual(residual: ParseResultResidual<E>) -> Self {
        match residual {
            ParseResultResidual::Deny => ParseResult::Deny,
            ParseResultResidual::Reject(e) => ParseResult::Reject(e),
        }
    }
}

#[macro_export]
macro_rules! expect_tt {
    ($token:expr, $($variant:ident),+) => {{
        let token = $token.clone();
        let tt = token.tt().to_string();

        let mut vs = String::new();
        $(
            let s = stringify!($variant);
            vs.push_str(s);
            vs.push_str("|");
        )+

        match tt.as_str() {
            $(
                stringify!($variant) => ParseResult::Accept(token),
            )+
            _ => {
                // let expected = format!("[{}]", vec![$(stringify!($variant)),+].join(" | "));
                ParseResult::Reject(CompilerError::UnexpectedToken(tt))
            }
        }
    }};
}

#[macro_export]
macro_rules! expect_value {
    ($expr:expr, $variant:ident) => {{
        let tok = $expr;
        match tok.clone() {
            Token::$variant(first, ..) => ParseResult::Accept(first),
            _ => {
                ParseResult::Reject(CompilerError::UnexpectedToken(tok.tt().to_string()))
            }
        }
    }};
}
