use crate::{
    ast::types::{
        BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt
    },
    diagnostic::{Diagnositics, span::Span},
    frontend::{
        err::ParseError,
        types::{Token, TokenValue, TypeIdent},
    },
};

pub struct Parser {
    tokens: Vec<Token>,
    pub diagnostics: Diagnositics,
    pos: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParseType {
   MustParse,
    TryParse,
}
enum ParseProcessError {
    TryNext,
    ErrorInMatch
}
impl Parser {
    pub fn new(tokens: Vec<Token>, diagnostics: Diagnositics) -> Self {
        Self {
            tokens,
            diagnostics,
            pos: 0,
        }
    }
    pub fn parse(&mut self) -> CompileUnit {
        self.parse_compile_unit()
    }
    fn peek(&self) -> Option<&Token> {
        self.tokens.get(self.pos)
    }
    fn next(&mut self) -> Option<&Token> {
        let token = self.tokens.get(self.pos);
        if token.is_some() {
            self.pos += 1;
        }
        token
    }
    fn advance(&mut self, n: usize) {
        self.pos += n;
        assert!(self.pos <= self.tokens.len());
    }
    fn back(&mut self, n: usize) {
        assert!(self.pos >= n);
        self.pos -= n;
    }
    fn last(&self) -> Option<&Token> {
        if self.pos == 0 {
            None
        } else {
            self.tokens.get(self.pos - 1)
        }
    }
    fn must_match_token(&mut self, expected: &TokenValue, diagnostic_text: &'static str) -> Result<(), ParseProcessError> {
        if let Some(t) = self.peek() {
            if &t.value == expected {
                self.advance(1);
                Ok(())
            } else {
                let token = self.next().unwrap().clone();
                self.diagnostics.add_from_frontend_error(
                    ParseError::UnexpectedToken(token.value, diagnostic_text),
                    token.span,
                );
                Err(ParseProcessError::ErrorInMatch)
            }
            
        } else {
            let span = self.next().unwrap().span;
            self.diagnostics
                .add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span);
            Err(ParseProcessError::ErrorInMatch)
        }
    }
    fn must_have_some(&mut self, diagnostic_text: &'static str) -> Result<(), ParseProcessError> {
        if self.peek().is_none() {
            let span = self.last().unwrap().span;
            self.diagnostics
                .add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span);
            return Err(ParseProcessError::ErrorInMatch);
        }
        Ok(())

    }
    fn until_next_token(&mut self, expected: &[TokenValue]) {
        while let Some(t) = self.peek() {
            if expected.contains(&t.value) {
                self.advance(1);
                break;
            }
            self.advance(1);
        }
    }
    fn parse_compile_unit(&mut self) -> CompileUnit {
        let mut global_decls = vec![];
        while self.peek().is_some() {
            if let Some(decl) = self.parse_global_decl_stmt() {
                global_decls.push(decl);
            } else {
                self.until_next_token(&[TokenValue::Semicolon, TokenValue::RBrace]);
            }
        }
        CompileUnit { global_decls }
    }

    fn parse_global_decl_stmt(&mut self) -> Option<GlobalDeclStmt> {
        assert!(self.peek().is_some());
        match self.parse_func_decl_stmt() {
            Ok(func_decl) => return Some(GlobalDeclStmt::FuncDecl(func_decl)),
            Err(ParseProcessError::ErrorInMatch) => {
                return None
            },
            _ => {}
        };
        match self.parse_var_decl_stmt(ParseType::MustParse) {
            Ok(var_decl) => return Some(GlobalDeclStmt::VarDecl(var_decl)),
            Err(ParseProcessError::ErrorInMatch) => {
                return None
            },
            _ => {}
        }
        let token = self.next().unwrap().clone();
        self.diagnostics.add_from_frontend_error(
            ParseError::UnexpectedToken(token.value, "ident"),
            token.span,
        );
        None
    }
    // fn until_next_stmt(&mut self) {
    //     // skip tokens until we find a semicolon or a right brace, which may indicate the end of the declaration
    //     while let Some(t) = self.peek() {
    //         if matches!(t.value, TokenValue::Semicolon | TokenValue::RBrace) {
    //             self.advance(1);
    //             break;
    //         }
    //         self.advance(1);
    //     }
    // }
    fn parse_type_and_name(&mut self, parse_type: ParseType) -> Result<(TypeIdent, String, Span, Span), ParseProcessError> {
        assert!(self.peek().is_some());
        let type_token = self.peek().unwrap().clone();
        let type_ident = match self.peek().unwrap().value.as_type_ident() {
            Some(ti) => ti,
            None => {
                if matches!(parse_type, ParseType::MustParse) {
                    let token = self.next().unwrap().clone();
                    self.diagnostics.add_from_frontend_error(
                        ParseError::UnexpectedToken(token.value, "type ident"),
                        token.span,
                    );
                    return Err(ParseProcessError::ErrorInMatch);
                }
                return Err(ParseProcessError::TryNext);
            },
        };
        let type_span = type_token.span;
        self.advance(1);
        let name = match self.peek().map(|t| t.value.as_ident()) {
            None => {
                self.diagnostics.add_from_frontend_error(
                    ParseError::ExpectButEof("ident"),
                    type_span,
                );
                return Err(ParseProcessError::ErrorInMatch);
            },
            Some(None) => {
                let next_span = self.peek().unwrap().span;
                self.diagnostics.add_from_frontend_error(
                    ParseError::CantCombineWith(type_token.value),
                    next_span
                );
                return Err(ParseProcessError::ErrorInMatch);
            }
            Some(Some(ident)) => ident,
        };
        let name_span = self.peek().unwrap().span;
        self.advance(1);
        Ok((type_ident, name, type_span, name_span))
    }
    fn parse_func_decl_stmt(&mut self) -> Result<FuncDeclStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        let (return_type, name, ret_type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?;
        if self
            .peek()
            .is_some_and(|t| matches!(t.value, TokenValue::LParen))
        {
        } else {
            self.back(2);
            return Err(ParseProcessError::TryNext);
        }
        // from here we can be sure it's a function declaration, so we can report error if the syntax is wrong
        let params = self.parse_param_list()?;
        let body = match self.peek().map(|t| &t.value) {
            Some(_) => self.parse_block_stmt(ParseType::MustParse)?,
            None => {
                let span = self.next().unwrap().span;
                self.diagnostics
                    .add_from_frontend_error(ParseError::ExpectButEof("function body"), span);
                return Err(ParseProcessError::ErrorInMatch);
            }
        };
        Ok(FuncDeclStmt {
            return_type: return_type.into(),
            name,
            params,
            body,
            ret_type_span,
            name_span,
        })
    }
    fn parse_param_list(&mut self) -> Result<Vec<Param>, ParseProcessError> {
        assert!(self.peek().is_some());
        if self.peek().unwrap().value != TokenValue::LParen {
            let token = self.next().unwrap().clone();
            self.diagnostics.add_from_frontend_error(
                ParseError::UnexpectedToken(token.value, "`(`"),
                token.span,
            );
            return Err(ParseProcessError::ErrorInMatch);
        }
        self.advance(1);
        let mut params = vec![];
        let mut last_is_var = false;
        while self.peek().is_some() {
            if self.peek().map(|t| &t.value) == Some(&TokenValue::RParen) {
                self.advance(1);
                break;
            }
            if last_is_var {
                self.must_match_token(&TokenValue::Comma, "`,` or `)`")
                    .inspect_err(|_| self.until_next_token(&[TokenValue::RBrace]))?;                
            }
            match self.parse_param() {
                Ok(param) => {
                    params.push(param);
                    last_is_var = true;
                }
                Err(_e) => {
                    self.until_next_token(&[TokenValue::RParen]);
                    if self.last().map(|t| &t.value) == Some(&TokenValue::RParen) {
                        break;
                    }
                }
            }
        }
        Ok(params)
    }
    fn parse_param(&mut self) -> Result<Param, ParseProcessError> {
        assert!(self.peek().is_some());
        let (param_type, name, type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?;
        Ok(Param {
            param_type: param_type.into(),
            name,
            name_span,
            type_span,
        })
    }
    // fn must_match_semicolon(&mut self) -> Option<()> {
    //     if self
    //         .peek()
    //         .is_some_and(|t| matches!(t.value, TokenValue::Semicolon))
    //     {
    //         self.advance(1);
    //         Some(())
    //     } else {
    //         let token = self.next().unwrap().clone();
    //         self.diagnostics
    //             .add_from_frontend_error(ParseError::UnexpectedToken(token.value, "`;`"), token.span);
    //         while let Some(t) = self.peek() {
    //             if matches!(t.value, TokenValue::Semicolon) {
    //                 self.advance(1);
    //                 break;
    //             }
    //             if matches!(t.value, TokenValue::RBrace) {
    //                 break;
    //             }
    //             self.advance(1);
    //         }
    //         None
    //     }
    // }
    fn parse_var_decl_stmt(&mut self, parse_type: ParseType) -> Result<VarDeclStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        let mut values = vec![];
        let (var_type, name, type_span, name_span) = match self.parse_type_and_name(parse_type) {
            Ok(res) => res,
            Err(_e) => {
                if matches!(parse_type, ParseType::TryParse) {
                    return Err(ParseProcessError::TryNext);
                } else {
                    return Err(ParseProcessError::ErrorInMatch);
                }
            }
        };
        values.push(VarDeclStmtValue { name, name_span });
        let mut last_name = true; // indicate whether the last parsed token is a variable name
        while let Some(t) = self.peek() {
            if matches!(t.value, TokenValue::Semicolon) { // statement end
                break;
            }
            if last_name { // expect a comma after a variable name
                self.must_match_token(&TokenValue::Comma, "`,` or `;`")?;
                last_name = false;
            }
            // check eof again
            if self.peek().is_none() {
                let span = self.last().unwrap().span;
                self.diagnostics
                    .add_from_frontend_error(ParseError::ExpectButEof("`,` or `;`"), span);
                break;
            }
            if let Some(ident) = self.peek().unwrap().value.as_ident() {
                let span = self.next().unwrap().span;
                values.push(VarDeclStmtValue { name: ident, name_span: span });
                last_name = true;
            } else {
                let token = self.next().unwrap().clone();
                self.diagnostics.add_from_frontend_error(
                    ParseError::CantCombineWith(TokenValue::TypeIdent(var_type)),
                    token.span,
                );
                return Err(ParseProcessError::ErrorInMatch);
            }
        }
        self.must_match_token(&TokenValue::Semicolon, "`;`")?;
        Ok(VarDeclStmt { values, type_span, data_type: var_type.into()  })
    }

    fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result<BlockStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        if self
            .peek()
            .unwrap().value != TokenValue::LBrace
        {
            if parse_type == ParseType::MustParse {
                let token = self.next().unwrap().clone();
                self.diagnostics.add_from_frontend_error(
                    ParseError::UnexpectedToken(token.value, "`{`"),
                    token.span,
                );
                return Err(ParseProcessError::ErrorInMatch);
            }
            return Err(ParseProcessError::TryNext);
        }
        self.advance(1);
        let mut statements = vec![];
        // println!("parse block stmt");
        loop {
            if self.peek().is_none() {
                let span = self.last().unwrap().span;
                self.diagnostics
                    .add_from_frontend_error(ParseError::ExpectButEof("`}`"), span);
                return Err(ParseProcessError::ErrorInMatch);
            }
            if self
                .peek()
                .map(|t| matches!(t.value, TokenValue::Semicolon))
                .unwrap()
            {
                // like a();;
                self.advance(1);
                continue;
            }
            if self
                .peek()
                .map(|t| matches!(t.value, TokenValue::RBrace))
                .unwrap()
            {
                self.advance(1);
                break;
            }
            // parse statement here
            match self.parse_stmt() {
                Ok(stmt) => statements.push(stmt),
                Err(_) => {
                    self.until_next_token(&[TokenValue::Semicolon, TokenValue::RBrace]);
                    if self.last().unwrap().value == TokenValue::RBrace {
                        break;
                    }
                }
            }
        }
        // println!("finish parse block stmt");
        Ok(BlockStmt {
            statements
        })
    }

    fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
        assert!(self.peek().is_some());
        match self.parse_var_decl_stmt(ParseType::TryParse) {
            Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        };
        match self.parse_return_stmt() {
            Ok(return_stmt) => return Ok(Statement::Return(return_stmt)),
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        };
        match self.parse_if_stmt() {
            Ok(if_stmt) => return Ok(Statement::If(if_stmt)),
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        }
        match self.parse_while_stmt() {
            Ok(while_stmt) => return Ok(Statement::While(while_stmt)),
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        }
        match self.parse_break_stmt() {
            Ok(break_stmt) => return Ok(Statement::Break(break_stmt)),
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        }
        match self.parse_continue_stmt() {
            Ok(continue_stmt) => return Ok(Statement::Continue(continue_stmt)),
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        }
        match self.parse_block_stmt(ParseType::TryParse) {
            Ok(block_stmt) => return Ok(Statement::Block(block_stmt)),
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        }
        match self.parse_expr() {
            Ok(expr) => {
                self.must_match_token(&TokenValue::Semicolon, "`;`")?;
                return Ok(Statement::Expr(expr))
            },
            Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
            Err(_) => {},
        }
        self.until_next_token(&[TokenValue::Semicolon]);
        Err(ParseProcessError::ErrorInMatch)
    }

    fn parse_return_stmt(&mut self) -> Result<ReturnStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        if self.peek().unwrap().value != TokenValue::Return {
             return Err(ParseProcessError::TryNext);
        }
        let span = self.next().unwrap().span;
        let value = if self
            .peek()
            .map(|t| matches!(t.value, TokenValue::Semicolon))
            .unwrap_or(false)
        {
            None
        } else {
            Some(self.parse_expr()?)
        };
        self.must_match_token(&TokenValue::Semicolon, "`;`")?;
        Ok(ReturnStmt {
            value,
            span,
        })
    }
    fn parse_if_stmt(&mut self) -> Result<IfStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        if self.peek().unwrap().value != TokenValue::If {
            return Err(ParseProcessError::TryNext);
        }
        self.advance(1);
        self.must_match_token(&TokenValue::LParen, "`(`")?;
        self.must_have_some("if condition expr")?;
        let condition = self.parse_expr()?;
        self.must_match_token(&TokenValue::RParen, "`)`")?;
        let then_branch;
        let mut ifelse_branch = vec![];
        let mut else_branch = None;
        self.must_have_some("if statement body")?;
        if self.peek().unwrap().value != TokenValue::LBrace {
            let stmt = self.parse_stmt()?;
            then_branch = BlockStmt { statements: vec![stmt] };
        } else {
            then_branch = self.parse_block_stmt(ParseType::MustParse)?;
        }
        loop {
            if self.peek().is_none() {
                break;
            }
            if self.peek().unwrap().value == TokenValue::Else {
                self.advance(1);
                self.must_have_some("else body")?;
                if self.peek().unwrap().value != TokenValue::If {
                    self.back(1);
                    break;
                }
                // else if
                self.advance(1);
                self.must_match_token(&TokenValue::LParen, "`(`")?;
                self.must_have_some("else if condition expr")?;
                let condition = self.parse_expr()?;
                self.must_match_token(&TokenValue::RParen, "`)`")?;
                let then_branch;
                if self.peek().unwrap().value != TokenValue::LBrace {
                    let stmt = self.parse_stmt()?;
                    then_branch = BlockStmt { statements: vec![stmt] };
                } else {
                    then_branch = self.parse_block_stmt(ParseType::MustParse)?;
                }
                ifelse_branch.push(IfElseBranch { condition, then_branch });
            } else {
                // if end ?
                break;
            }
        }
        if self.peek().is_some_and(|t| t.value == TokenValue::Else) {
            // Parse else branch
            self.advance(1);
            self.must_have_some("else body")?;
            if self.peek().unwrap().value != TokenValue::LBrace {
                let stmt = self.parse_stmt()?;
                else_branch = Some(BlockStmt { statements: vec![stmt] });
            } else {
                else_branch = Some(self.parse_block_stmt(ParseType::MustParse)?);
            }
        }
        Ok(IfStmt {
            condition,
            then_branch,
            ifelse_branch,
            else_branch,
        })
    }

    fn parse_while_stmt(&mut self) -> Result<WhileStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        if self.peek().unwrap().value != TokenValue::While {
            return Err(ParseProcessError::TryNext);
        }
        self.advance(1);
        self.must_match_token(&TokenValue::LParen, "`(`")?;
        self.must_have_some("while condition expr")?;
        let condition = self.parse_expr()?;
        self.must_match_token(&TokenValue::RParen, "`)`")?;
        let body;
        if self.peek().unwrap().value != TokenValue::LBrace {
            let stmt = self.parse_stmt()?;
            body = BlockStmt { statements: vec![stmt] };
        } else {
            body = self.parse_block_stmt(ParseType::MustParse)?;
        }
        Ok(WhileStmt {
            condition,
            body,
        })
    }

    fn parse_break_stmt(&mut self) -> Result<BreakStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        let start_span = self.peek().unwrap().span;
        if self.peek().unwrap().value == TokenValue::Break {
            self.advance(1);
            self.must_match_token(&TokenValue::Semicolon, "`;`")?;
            Ok(BreakStmt {
                span: start_span,
            })
        } else {
            Err(ParseProcessError::TryNext)
        }
    }

    fn parse_continue_stmt(&mut self) -> Result<ContinueStmt, ParseProcessError> {
        assert!(self.peek().is_some());
        let start_span = self.peek().unwrap().span;
        if self.peek().unwrap().value == TokenValue::Continue {
            self.advance(1);
            self.must_match_token(&TokenValue::Semicolon, "`;`")?;
            Ok(ContinueStmt {
                span: start_span,
            })
        } else {
            Err(ParseProcessError::TryNext)
        }
    }
    // fn parse_expr_tail(&mut self, left: Expr) -> Option<Expr> {
    //    match self.peek() {
    //        None => Some(left),
    //        Some(t1) => {
    //            // TODO: add delimiter judge to support better error recovery
    //            let op = BinaryOp::from_token_value(&t1.value)?;
    //            match op {
    //                BinaryOp::Add
    //            }
    //            let right = self.parse_term()?;
    //            let expr = Expr { value: ExprValue::BinaryOp { lhs: Box::new(left), op, rhs: Box::new(right) }, span: Span::from_two(left.span, right.span) };
    //            self.parse_expr_tail(expr)
    //        }
    //    }
    // }
    fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        let token = self.next().unwrap().clone();
        match token.value {
            TokenValue::Ident(name) => {
                if self
                    .peek()
                    .is_some_and(|t| matches!(t.value, TokenValue::LParen))
                {
                    self.advance(1);
                    let mut args = vec![];
                    loop {
                        match self.peek() {
                            Some(t) if matches!(t.value, TokenValue::RParen) => {
                                let end_span = t.span;
                                self.advance(1);
                                return Ok(Expr {
                                    value: ExprValue::FuncCall(name, args),
                                    span: Span::from_two(token.span, end_span),
                                });
                            }
                            Some(_) => {}
                            None => {
                                self.diagnostics.add_from_frontend_error(
                                    ParseError::ExpectButEof("`)`"),
                                    token.span,
                                );
                                return Err(ParseProcessError::ErrorInMatch);
                            }
                        }
                        args.push(self.parse_expr()?);
                        match self.peek() {
                            Some(t) if matches!(t.value, TokenValue::Comma) => {
                                self.advance(1);
                            }
                            Some(t) if matches!(t.value, TokenValue::RParen) => {
                                let end_span = t.span;
                                self.advance(1);
                                return Ok(Expr {
                                    value: ExprValue::FuncCall(name, args),
                                    span: Span::from_two(token.span, end_span),
                                });
                            }
                            Some(_) => {
                                let token = self.next().unwrap().clone();
                                self.diagnostics.add_from_frontend_error(
                                    ParseError::UnexpectedToken(token.value, "`,` or `)`"),
                                    token.span,
                                );
                                return Err(ParseProcessError::ErrorInMatch);
                            }
                            None => {
                                self.diagnostics.add_from_frontend_error(
                                    ParseError::ExpectButEof("`)`"),
                                    token.span,
                                );
                                return Err(ParseProcessError::ErrorInMatch);
                            }
                        }
                    }
                }
                Ok(Expr {
                    value: ExprValue::Var(name),
                    span: token.span,
                })
            },
            TokenValue::IntLit(value) => Ok(Expr {
                value: ExprValue::IntLit(value),
                span: token.span,
            }),
            TokenValue::LParen => {
                let expr = match self.peek() {
                    Some(_) => self.parse_expr()?,
                    None => {
                        self.diagnostics.add_from_frontend_error(
                            ParseError::ExpectButEof("expression"),
                            token.span,
                        );
                        return Err(ParseProcessError::ErrorInMatch);
                    }
                };
                match self.peek() {
                    Some(t) if matches!(t.value, TokenValue::RParen) => {
                        let end_span = t.span;
                        self.advance(1);
                        Ok(Expr {
                            span: Span::from_two(token.span, end_span),
                            ..expr
                        })
                    }
                    Some(_) => {
                        let token = self.next().unwrap().clone();
                        self.diagnostics.add_from_frontend_error(
                            ParseError::UnexpectedToken(token.value, "`)`"),
                            token.span,
                        );
                        Err(ParseProcessError::ErrorInMatch)
                    }
                    None => {
                        self.diagnostics
                            .add_from_frontend_error(ParseError::ExpectButEof("`)`"), expr.span);
                        Err(ParseProcessError::ErrorInMatch)
                    }
                }
            }
            _ => {
                self.diagnostics.add_from_frontend_error(
                    ParseError::UnexpectedToken(token.value, "expression"),
                    token.span,
                );
                Err(ParseProcessError::ErrorInMatch)
            }
        }
    }
    fn parse_unary(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        let token = self.peek().unwrap().clone();
        match token.value {
            TokenValue::Plus => {
                self.advance(1);
                let expr = match self.peek() {
                    Some(_) => self.parse_unary()?,
                    None => {
                        self.diagnostics.add_from_frontend_error(
                            ParseError::ExpectButEof("expression"),
                            token.span,
                        );
                        return Err(ParseProcessError::ErrorInMatch);
                    }
                };
                let span = Span::from_two(token.span, expr.span);
                Ok(Expr {
                    value: ExprValue::UnaryOp {
                        op: UnaryOp::Add,
                        operand: Box::new(expr),
                    },
                    span,
                })
            }
            TokenValue::Minus => {
                self.advance(1);
                let rhs = match self.peek() {
                    Some(_) => self.parse_unary()?,
                    None => {
                        self.diagnostics.add_from_frontend_error(
                            ParseError::ExpectButEof("expression"),
                            token.span,
                        );
                        return Err(ParseProcessError::ErrorInMatch);
                    }
                };
                let span = Span::from_two(token.span, rhs.span);
                Ok(Expr {
                    value: ExprValue::UnaryOp {
                        op: UnaryOp::Sub,
                        operand: Box::new(rhs),
                    },
                    span,
                })
            }
            TokenValue::Not => {
                self.advance(1);
                let rhs = match self.peek() {
                    Some(_) => self.parse_unary()?,
                    None => {
                        self.diagnostics.add_from_frontend_error(
                            ParseError::ExpectButEof("expression"),
                            token.span,
                        );
                        return Err(ParseProcessError::ErrorInMatch);
                    }
                };
                let span = Span::from_two(token.span, rhs.span);
                Ok(Expr {
                    value: ExprValue::UnaryOp {
                        op: UnaryOp::Not,
                        operand: Box::new(rhs),
                    },
                    span,
                })
            }
            _ => self.parse_primary(),
        }
    }
    fn parse_multiplicative(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        let mut left = self.parse_unary()?;
        while let Some(t) = self.peek() {
            let op = match t.value {
                TokenValue::Star => BinaryOp::Mul,
                TokenValue::Slash => BinaryOp::Div,
                TokenValue::Percent => BinaryOp::Mod,
                _ => break,
            };
            self.advance(1);
            let right = match self.peek() {
                Some(_) => self.parse_unary()?,
                None => {
                    self.diagnostics
                        .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
                    return Err(ParseProcessError::ErrorInMatch);
                }
            };
            let span = Span::from_two(left.span, right.span);
            left = Expr {
                value: ExprValue::BinaryOp {
                    lhs: Box::new(left),
                    op,
                    rhs: Box::new(right),
                },
                span,
            };
        }
        Ok(left)
    }
    fn parse_additive(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        let mut left = self.parse_multiplicative()?;
        while let Some(t) = self.peek() {
            let op = match t.value {
                TokenValue::Plus => BinaryOp::Add,
                TokenValue::Minus => BinaryOp::Sub,
                _ => break,
            };
            self.advance(1);
            let right = match self.peek() {
                Some(_) => self.parse_multiplicative()?,
                None => {
                    self.diagnostics
                        .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
                    return Err(ParseProcessError::ErrorInMatch);
                }
            };
            let span = Span::from_two(left.span, right.span);
            left = Expr {
                value: ExprValue::BinaryOp {
                    lhs: Box::new(left),
                    op,
                    rhs: Box::new(right),
                },
                span,
            };
        }
        Ok(left)
    }
    fn parse_relational(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        let mut left = self.parse_additive()?;
        while let Some(t) = self.peek() {
            let op = match t.value {
                TokenValue::Less => BinaryOp::Less,
                TokenValue::Greater => BinaryOp::Greater,
                TokenValue::LessEqual => BinaryOp::LessEqual,
                TokenValue::GreaterEqual => BinaryOp::GreaterEqual,
                TokenValue::DoubleEqual => BinaryOp::Equal,
                TokenValue::NotEqual => BinaryOp::NotEqual,
                _ => break,
            };
            self.advance(1);
            let right = match self.peek() {
                Some(_) => self.parse_additive()?,
                None => {
                    self.diagnostics
                        .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
                    return Err(ParseProcessError::ErrorInMatch);
                }
            };
            let span = Span::from_two(left.span, right.span);
            left = Expr {
                value: ExprValue::BinaryOp {
                    lhs: Box::new(left),
                    op,
                    rhs: Box::new(right),
                },
                span,
            };
        }
        Ok(left)
    }
    fn parse_logical(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        let mut left = self.parse_relational()?;
        while let Some(t) = self.peek() {
            let op = match t.value {
                TokenValue::Or => BinaryOp::Or,
                TokenValue::And => BinaryOp::And,
                _ => break,
            };
            self.advance(1);
            let right = match self.peek() {
                Some(_) => self.parse_relational()?,
                None => {
                    self.diagnostics
                        .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
                    return Err(ParseProcessError::ErrorInMatch);
                }
            };
            let span = Span::from_two(left.span, right.span);
            left = Expr {
                value: ExprValue::BinaryOp {
                    lhs: Box::new(left),
                    op,
                    rhs: Box::new(right),
                },
                span,
            };
        }
        Ok(left)
    }
    fn parse_assign(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        let is_assign = matches!(
            (self.tokens.get(self.pos), self.tokens.get(self.pos + 1)),
            (
                Some(Token {
                    value: TokenValue::Ident(_),
                    ..
                }),
                Some(Token {
                    value: TokenValue::Equal,
                    ..
                })
            )
        );
        if !is_assign {
            return self.parse_logical();
        }

        let lvalue_token = self.next().unwrap().clone();
        let name = lvalue_token.value.as_ident().unwrap();
        self.advance(1);
        let rvalue = match self.peek() {
            Some(_) => self.parse_assign()?,
            None => {
                self.diagnostics.add_from_frontend_error(
                    ParseError::ExpectButEof("expression"),
                    lvalue_token.span,
                );
                return Err(ParseProcessError::ErrorInMatch);
            }
        };
        let lvalue = Expr {
            value: ExprValue::Var(name),
            span: lvalue_token.span,
        };
        let span = Span::from_two(lvalue.span, rvalue.span);
        Ok(Expr {
            value: ExprValue::Assign {
                lvalue: Box::new(lvalue),
                rvalue: Box::new(rvalue),
            },
            span,
        })
    }
    /*
       expr
           := assign

       assign
           := logical
           | IDENT "=" assign
        logical
           := relational
           | logical "||" relational
           | logical "&&" relational
       relational
           := additive
           | relational "<" additive
           | relational ">" additive
           | relational "<=" additive
           | relational ">=" additive
           | relational "==" additive
           | relational "!=" additive

       additive
           := multiplicative
           | additive "+" multiplicative
           | additive "-" multiplicative

       multiplicative
           := unary
           | multiplicative "*" unary
           | multiplicative "/" unary

       unary
           := primary
           | "+" unary
           | "-" unary

       primary
           := IDENT
           | NUMBER
           | "(" expr ")"
    */
    fn parse_expr(&mut self) -> Result<Expr, ParseProcessError> {
        assert!(self.peek().is_some());
        self.parse_assign()
    }
}

#[cfg(test)]
mod tests {
    use std::io::BufRead;
    use std::path::Path;
    use std::fs::File;
    use crate::ast::graph::AstGraphExt;
    use crate::frontend::lexer::Lexer;
    use crate::utils::case_list::CaseList;
    use crate::utils::num_sequence::NumberSequence;

    pub use super::*;
    fn test_case(case_str: &str) {
        let case_sequence = NumberSequence::from_str(case_str).unwrap();
        let case_list = CaseList::from_dir(&Path::new("./testcases")).unwrap();
        let mut error_case_cnt = 0;
        for case_no in case_sequence {
            let case_path = case_list.get_case_path(case_no).unwrap();
            println!("{}", case_path.display());
            let file = File::open(&case_path).unwrap();
            let mut buf_reader = std::io::BufReader::new(file);
            let mut lexer = Lexer::new();
            let mut full_text = String::new();
            loop {
                let mut line = String::new();
                let bytes_read = buf_reader.read_line(&mut line).unwrap();
                if bytes_read == 0 {
                    break;
                }
                full_text.push_str(&line);
                lexer.parse_next_str(&line);
            }
            let (tokens, diagnostics) = lexer.finish();
            let mut is_error = false;
            if !diagnostics.is_empty() {
                diagnostics.print(&format!("{}", case_path.display()), &full_text);
                is_error = true;
            }
            let mut parser = Parser::new(tokens, diagnostics);
            let compile_unit = parser.parse_compile_unit();
            let dot = compile_unit.to_dot();
            let case_name = case_list.get_case_name(case_no).unwrap().strip_suffix(".c").unwrap();
            std::fs::write(format!("output/{}.dot", case_name), dot).unwrap();
            if !parser.diagnostics.is_empty() {
                parser.diagnostics.print(&format!("{}", case_path.display()), &full_text);
                is_error = true;
            }
            if is_error {
                error_case_cnt += 1;
            }
        }
        if error_case_cnt > 0 {
            panic!("Found {} cases with errors", error_case_cnt);
        }

    }
    #[test]
    fn test_expr() {
        test_case("0-3,14-25");
        // test_case("0-3,14-25");
    }

    #[test]
    fn test_if_while() {
        test_case("26-32,34-41,46-51,57");
    }

    #[test]
    fn test_error() {
        test_case("999");
    }
}
