use crate::lexer::*;
//use libwild::*;
use std::collections::HashMap;

#[derive(Debug, Clone, PartialEq)]
pub enum AstNode {
    Integer(IntegerExpr),
    Float(FloatExpr),
    String(StringExpr),
    Identifier(IdentifierExpr),
    Binary(BinaryExpr)
}

type Node = Box<AstNode>;

trait IntoNode {
    fn into_node(self) -> Node;
}

// 导入过程宏
use node_macro::IntoNode;

macro_rules! new_node {
    // 匹配任何结构体构造语法
    ($struct_name:ident { $($field:ident : $value:expr),* $(,)? }) => {
        $struct_name { $($field: $value),* }.into_node()
    };
}

#[derive(Debug, Clone, PartialEq)]
pub struct Value<T> {
    pub value: T,
    pub token: Token
}

impl<T> Value<T> {
    pub fn new(value: T, token: Token) -> Self {
        Value {
            value: value,
            token: token
        }
    }
}

#[derive(Debug, Clone, PartialEq, IntoNode)]
#[node_variant("Integer")]
pub struct IntegerExpr {
    pub value: Value<isize>
}

#[derive(Debug, Clone, PartialEq, IntoNode)]
#[node_variant("Float")]
pub struct FloatExpr {
    pub value: Value<f64>
}

#[derive(Debug, Clone, PartialEq, IntoNode)]
#[node_variant("String")]
pub struct StringExpr {
    pub value: Value<String>
}

#[derive(Debug, Clone, PartialEq, IntoNode)]
#[node_variant("Identifier")]
pub struct IdentifierExpr {
    pub name: Value<String>
}

#[derive(Debug, Clone, PartialEq, IntoNode)]
#[node_variant("Binary")]
pub struct BinaryExpr {
    pub op: Value<String>,
    pub left: Node,
    pub right: Node
}

pub struct Parser {
    idx: usize,
    idx_list: HashMap<String, usize>,
    tokens: Vec<Token>,
    ast: Vec<Node>
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        let parser = Parser {
            idx: 0,
            idx_list: HashMap::new(),
            tokens: tokens,
            ast: Vec::new()
        };
        
        return parser
    }
    
    pub fn start(&mut self) -> Option<Vec<Node>> {
        //println!("{:?}", self.tokens);
        
        return self.loop_parser();
    }
    
    fn integer(&mut self) -> Option<Node> {
        let idx = self.idx;
        if let Some(token) = self.token_get() {
            if token.kind == Tkn::Integer {
                return Some(new_node!(IntegerExpr {
                    value: Value::new(
                        token.value.parse::<isize>().unwrap(),
                        token
                    )
                }));
            }
            self.idx = idx;
            return None;
        }
        self.idx = idx;
        return None;
    }
    
    fn float(&mut self) -> Option<Node> {
        let idx = self.idx;
        if let Some(token) = self.token_get() {
            if token.kind == Tkn::Float {
                return Some(new_node!(FloatExpr {
                    value: Value::new(
                        token.value.parse::<f64>().unwrap(),
                        token
                    )
                }));
            }
            self.idx = idx;
            return None;
        }
        self.idx = idx;
        return None;
    }
    
    fn string(&mut self) -> Option<Node> {
        let idx = self.idx;
        if let Some(token) = self.token_get() {
            if token.kind == Tkn::String {
                return Some(new_node!(StringExpr {
                    value: Value::new(
                        token.value.clone(),
                        token
                    )
                }));
            }
            self.idx = idx;
            return None;
        }
        self.idx = idx;
        return None;
    }
    
    fn identifier(&mut self) -> Option<Node> {
        let idx = self.idx;
        if let Some(token) = self.token_get() {
            if token.kind == Tkn::Identifier {
                return Some(new_node!(IdentifierExpr {
                    name: Value::new(
                        token.value.clone(),
                        token
                    )
                }));
            }
            self.idx = idx;
            return None;
        }
        self.idx = idx;
        return None;
    }
    
    fn value(&mut self) -> Option<Node> {
        if let Some(node) = self.integer() {
            return Some(node);
        }
        
        if let Some(node) = self.float() {
            return Some(node);
        }
        
        if let Some(node) = self.string() {
            return Some(node);
        }
        
        if let Some(node) = self.identifier() {
            return Some(node);
        }
        
        return None;
    }
    
    fn expr0(&mut self) -> Option<Node> {
        return self.value();
    }
    
    // 解析*、/、%
    fn expr1(&mut self) -> Option<Node> {
        let expr1 = self.expr0();
        if expr1 == None {
            return None;
        }
        
        let idx = self.idx;
        let op = self.token_get();
        
        if op == None {
            self.idx = idx;
            return None;
        }
        
        let expr2 = self.expr1();
        
        if let Some(op2) = op {
            if (op2.kind == Tkn::Multiply || op2.kind == Tkn::Slash || op2.kind == Tkn::Remainder) && expr2.is_some() {
                return Some(new_node!(BinaryExpr {
                    op: Value::new(op2.value.clone(), op2),
                    left: expr1?,
                    right: expr2?
                }));
            }
        }
        
        self.idx = idx;
        return expr1;
    }
    
    // 解析+、-
    fn expr2(&mut self) -> Option<Node> {
        let expr1 = self.expr1();
        if expr1 == None {
            return None;
        }
        
        let idx = self.idx;
        let op = self.token_get();
        
        if op == None {
            self.idx = idx;
            return None;
        }
        
        let expr2 = self.expr2();
        
        if let Some(op2) = op {
            if (op2.kind == Tkn::Plus || op2.kind == Tkn::Minus) && expr2.is_some() {
                return Some(new_node!(BinaryExpr {
                    op: Value::new(op2.value.clone(), op2),
                    left: expr1?,
                    right: expr2?
                }));
            }
        }
        
        self.idx = idx;
        return expr1;
    }
    
    fn loop_parser(&mut self) -> Option<Vec<Node>> {
        let mut result = Vec::new();
        
        loop {
            if let Some(node) = self.parser() {
                result.push(node);
            } else {
                break;
            }
        }
        
        return Some(result);
    }
    
    fn parser(&mut self) -> Option<Node> {
        if let Some(node) = self.expr2() {
            return Some(node);
        }
        
        return None;
    }
    
    fn record_idx(&mut self, name: &str) {
        self.idx_list.insert(name.to_string(), self.idx);
    }
    
    fn recover_idx(&mut self, name: &str) {
        if let Some(idx) = self.idx_list.get(&name.to_string()) {
            self.idx = *idx;
        }
    }
    
    fn token(&mut self) -> Option<Token> {
        let token = self.tokens.get(self.idx);
        self.idx += 1;
        token.cloned()
    }
    
    fn token_get(&mut self) -> Option<Token> {
        loop {
            if let Some(token) = self.token() {
                if token.kind != Tkn::Space && token.kind != Tkn::Tab && token.kind != Tkn::Line {
                    return Some(token);
                }
            } else {
                return None;
            }
        }
    }
}