use regex::*;
use indexmap::IndexMap as OrderedMap;
use unicode_segmentation::UnicodeSegmentation;

#[allow(dead_code)]
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub enum Tkn {
    Integer,                     // 整数
    Float,                       // 浮点数
    String,                       // 字符串
    Keyword,                    // 关键字
    Identifier,                    // 标识符
    Plus,                        // +
    Minus,                      // - 
    Multiply,                    // * 
    Slash,                      // /
    Remainder,                 // %
    
    And,                        // &
    Or,                          // |
    ExclusiveOr,                 // ^
    ShiftLeft,                    // <<
    ShiftRight,                   // >>
    AndNot,                     // &^
    
    AddAssign,                  // +=
    SubtractAssign,              // -=
    MultiplyAssign,              // *=
    QuotientAssign,              // /+
    RemainderAssign,            // %=
    
    LogicalAnd,                  // &&
    LogicalOr,                    // ||
    Increment,                    // ++
    Decrement,                   // --
    
    Equal,                         // ==
    Less,                         // <
    Greater,                       // >
    Assign,                        // =
    Not,                           // !
    
    BitwiseNot,                    // ~
    
    NotEqual,                      // !=
    LessOrEqual,                  // <=
    GreaterOrEqual,               // >=
    
    LeftParenthesis,              // (
    LeftBracket,                  // [
    LeftBrace,                    // {
    
    RightParenthesis,            // )
    RightBracket,                // ]
    RightBrace,                  // }
    
    Comma,                      // ,
    Period,                       // .
    Colon,                        // :
    Semicolon,                   // ;
    QuestionMark,               // ?
    Space,                       // 空格
    Tab,                         // TAB键
    Line,                        // 换行(\n)
}

#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct Token {
    pub kind: Tkn,
    pub value: String,
    pub line: usize,
    pub column: usize,
    pub line_quantity: usize
}

pub struct Lexer {
    code: String,
    line: usize,
    column: usize,
    line_quantity: usize,
    match_list: OrderedMap<Tkn, String>,
    result: Vec<Token>
}

impl Lexer {
    pub fn new(code: String) -> Self {
        let mut lexer = Lexer {
            code: code,
            line: 0,
            column: 0,
            line_quantity: 0,
            match_list: OrderedMap::new(),
            result: Vec::new()
        };
        lexer.init();
        lexer
    }
    
    fn init(&mut self) {
        self.match_list.insert(Tkn::Integer, r"^[-]?(0|[1-9][0-9]*)".to_string());                     // 整数
        self.match_list.insert(Tkn::Float, r"^-?\d+\.\d+$".to_string());                   // 浮点数
        self.match_list.insert(Tkn::String, r#"^"((?:[^"\\]|\\.)*)""#.to_string());        // 支持转义的字符串
        self.match_list.insert(Tkn::Keyword, r"^\b(if|else|while|for|fn|let|return|struct|enum|impl|pub|use|mod)\b$".to_string()); // 关键字示例
        self.match_list.insert(Tkn::Identifier, r"^[a-zA-Z_][a-zA-Z0-9_]*".to_string()); // 标识符
        
        // 逻辑运算符
        self.match_list.insert(Tkn::LogicalAnd, r"^&&".to_string());                   // &&
        self.match_list.insert(Tkn::LogicalOr, r"^\|\|".to_string());                  // ||
        self.match_list.insert(Tkn::Not, r"^!".to_string());                           // !
        self.match_list.insert(Tkn::BitwiseNot, r"^~".to_string());                    // ~
        
        // 自增自减
        self.match_list.insert(Tkn::Increment, r"^\+\+".to_string());                  // ++
        self.match_list.insert(Tkn::Decrement, r"--".to_string());                    // --
        
        // 比较运算符
        self.match_list.insert(Tkn::Equal, r"^==".to_string());                        // ==
        self.match_list.insert(Tkn::NotEqual, r"^!=".to_string());                     // !=
        self.match_list.insert(Tkn::LessOrEqual, r"^<=".to_string());                  // <=
        self.match_list.insert(Tkn::GreaterOrEqual, r"^>=".to_string());               // >=
        self.match_list.insert(Tkn::Less, r"^<".to_string());                          // <
        self.match_list.insert(Tkn::Greater, r"^>".to_string());                       // >
        
        // 赋值运算符
        self.match_list.insert(Tkn::AddAssign, r"^\+=".to_string());                   // +=
        self.match_list.insert(Tkn::SubtractAssign, r"^-=".to_string());               // -=
        self.match_list.insert(Tkn::MultiplyAssign, r"^\*=".to_string());              // *=
        self.match_list.insert(Tkn::QuotientAssign, r"^/=".to_string());               // /=
        self.match_list.insert(Tkn::RemainderAssign, r"^%=".to_string());              // %=
        self.match_list.insert(Tkn::Assign, r"^=".to_string());                        // =
        
        // 位运算符
        self.match_list.insert(Tkn::And, r"^&".to_string());                           // &
        self.match_list.insert(Tkn::Or, r"^\|".to_string());                           // |
        self.match_list.insert(Tkn::ExclusiveOr, r"^\^".to_string());                  // ^
        self.match_list.insert(Tkn::ShiftLeft, r"^<<".to_string());                    // <<
        self.match_list.insert(Tkn::ShiftRight, r"^>>".to_string());                   // >>
        self.match_list.insert(Tkn::AndNot, r"^&^".to_string());                       // &^

        // 括号和大括号
        self.match_list.insert(Tkn::LeftParenthesis, r"^\(".to_string());              // (
        self.match_list.insert(Tkn::RightParenthesis, r"^\)".to_string());             // )
        self.match_list.insert(Tkn::LeftBracket, r"^\[".to_string());                  // [
        self.match_list.insert(Tkn::RightBracket, r"^\]".to_string());                 // ]
        self.match_list.insert(Tkn::LeftBrace, r"^\{".to_string());                    // {
        self.match_list.insert(Tkn::RightBrace, r"^\}".to_string());                   // }

        // 标点符号
        self.match_list.insert(Tkn::Comma, r"^,".to_string());                         // ,
        self.match_list.insert(Tkn::Period, r"^\.".to_string());                       // .
        self.match_list.insert(Tkn::Colon, r"^:".to_string());                         // :
        self.match_list.insert(Tkn::Semicolon, r"^;".to_string());                     // ;
        self.match_list.insert(Tkn::QuestionMark, r"^\?".to_string());                 // ?
        
        // 算术运算符
        self.match_list.insert(Tkn::Plus, r"^\+".to_string());                         // +
        self.match_list.insert(Tkn::Minus, r"^-".to_string());                         // -
        self.match_list.insert(Tkn::Multiply, r"^\*".to_string());                     // *
        self.match_list.insert(Tkn::Slash, r"^/".to_string());                         // /
        self.match_list.insert(Tkn::Remainder, r"^%".to_string());                     // %
        
        self.match_list.insert(Tkn::Space, r"^[ \t]".to_string());                         // 空格
        //self.match_list.insert(Tkn::Tab, r"^    ".to_string());                            // TAB
        self.match_list.insert(Tkn::Line, r"^\r?\n".to_string());                           // 换行(\n)
    }
    
    fn add_token(&mut self, kind: Tkn, value: String) {
        self.result.push(Token {
            kind: kind,
            value: value,
            line: self.line,
            column: self.column,
            line_quantity: self.line_quantity
        })
    }
    
    pub fn start(&mut self) -> Result<Vec<Token>, String> {
        let mut ok = true;
        let mut code = self.code.clone();
        
        loop {
            if code.is_empty() {
                break;
            }
            
            let mut status = false;
            
            for (tkn, value) in self.match_list.iter() {
                
                let re = Regex::new(value).expect("创建正则失败");
                
                if let Some(caps) = re.captures(&code) {
                    if let Some(v) = caps.get(0) {
                        let s = v.as_str().to_string();
                        
                        if tkn.clone() == Tkn::Line {
                            self.line += 1;
                            self.column = 0;
                            self.line_quantity = 0;
                        }
                        
                        if tkn.clone() == Tkn::String {
                            self.add_token(tkn.clone(), caps[1].to_string());
                        } else {
                            self.add_token(tkn.clone(), caps[0].to_string());
                        }
                        
                        self.line_quantity += 1;
                        self.column += s.graphemes(true).count();
                        
                        code = (&code[v.end()..]).to_string();
                        
                        status = true;
                        break;
                    }
                }
            }
            
            if !status {
                ok = false;
                break;
            }
        }
        
        if !ok {
            return Err(format!("词法分析失败, 在第{}行,第{}个字符", self.line, self.column));
        }
        
        return Ok(self.result.clone());
    }
}