use std::fs::{self, File};
use std::io::BufRead;
use std::io::BufReader;
use std::path::PathBuf;
#[allow(unused)]
use log::info;
use regex::Regex;
use ropey::Rope;
use tower_lsp::lsp_types::Url;
use sv_parser::{unwrap_locate, unwrap_node, EventIter, ListOfParamAssignments, Locate, NodeEvent, ParamAssignment, ParameterDeclaration, RefNode, SyntaxTree};

use crate::core::hdlparam::{AssignType, Position, Range};
use crate::sources::{recovery_sv_parse_with_retry, LSPSupport};
use crate::utils::to_escape_path;

use super::hdlparam::{self, FastHdlparam, InstParameter, InstPort, Macro};

macro_rules! advance_until_leave {
    ($tokens:ident, $tree:ident, $event_iter:ident, $node:path) => {{
        let mut result: Option<RefNode> = None;
        while let Some(event) = $event_iter.next() {
            match event {
                NodeEvent::Leave(x) => match x {
                    $node(node) => {
                        result = Some($node(node));
                        break;
                    }
                    RefNode::Locate(node) => {
                        $tokens.push(' ');
                        $tokens.push_str($tree.get_str(node).unwrap());
                    }
                    _ => (),
                },
                NodeEvent::Enter(_) => (),
            }
        }
        result
    }};
}

macro_rules! skip_until_enter {
    ($tree:ident, $event_iter:ident, $node:path, $type:ty) => {{
        let mut result: Option<$type> = None;
        while let Some(event) = $event_iter.next() {
            match event {
                NodeEvent::Enter(x) => match x {
                    $node(node) => {
                        result = Some(node);
                        break;
                    }
                    _ => (),
                },
                NodeEvent::Leave(_) => (),
            }
        }
        result
    }};
}

#[allow(unused)]
pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
    // The path of SystemVerilog source file
    let path = PathBuf::from(path);
    // The list of include paths
    let includes: Vec<PathBuf> = Vec::new();

    let text = match fs::read_to_string(&path) {
        Ok(text) => text,
        Err(_) => return None
    };

    let doc = Rope::from_str(&text);
    let uri = Url::from_file_path(&path).unwrap();
    let result = recovery_sv_parse_with_retry(&doc, &uri, &None, &includes);
    
    if let Some((syntax_tree, _)) = result {
        if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &path) {
            return Some(fast);
        }
    }

    None
}

pub fn make_fast_from_syntaxtree(
    syntax_tree: &SyntaxTree,
    path: &PathBuf
) -> Result<FastHdlparam, std::io::Error> {
    // 对不同操作系统文件路径的支持
    let path = to_escape_path(path);

    let mut fast: FastHdlparam = FastHdlparam {
        fast_macro: Macro {
            defines: Vec::new(),
            errors: Vec::new(),
            includes: get_includes(&path),
            invalid: Vec::new()
        },
        content: Vec::new(),
        file_type: "common".to_string()
    };
    let mut ansi_port_last_dir = "";

    // &SyntaxTree is iterable
    let doc = Rope::from_str(syntax_tree.text.text());

    // 上一个 module 可以在 fast 的 content 的最后一个中找到

    for node in syntax_tree {
        match node {
            RefNode::TextMacroDefinition(x) => {
                if let Some(start) = unwrap_node!(x, TextMacroDefinition) {
                    let start = get_identifier(start).unwrap();
                    let start_pos = get_position(&doc, start, 0);

                    let name = if let Some(name) = unwrap_node!(x, TextMacroName) {
                        let name = get_identifier(name).unwrap();
                        syntax_tree.get_str(&name).unwrap()
                    } else {
                        "unknown"
                    };

                    let mut params_vec = Vec::new();
                    if let Some(RefNode::ListOfFormalArguments(x)) = unwrap_node!(x, ListOfFormalArguments) {
                        for node in x {
                            if let RefNode::FormalArgument(x) = node {
                                let param_name = if let Some(param_name) = unwrap_node!(x, SimpleIdentifier) {
                                    let param_name = get_identifier(param_name).unwrap();
                                    syntax_tree.get_str(&param_name).unwrap()
                                } else {
                                    "unknown"
                                };
                                let param_val = match unwrap_node!(x, DefaultText) {
                                    Some(RefNode::DefaultText(x)) => syntax_tree.get_str(&x.nodes.0).unwrap(),
                                    _ => "Unknown"
                                };
                                params_vec.push(crate::core::hdlparam::DefineParam { name: param_name.to_string(), value: param_val.to_string() });
                            }
                        }
                    }

                    let (end_pos, replacement) = if let Some(RefNode::MacroText(x)) = unwrap_node!(x, MacroText) {
                        let replacement = x.nodes.0;
                        (get_position(&doc, replacement,replacement.len), syntax_tree.get_str(&replacement).unwrap())
                    } else {
                        (get_position(&doc, start, start.len), "unknown")
                    };
                    let define_range = Range { start: start_pos, end: end_pos };

                    fast.add_define(name, replacement, define_range, params_vec);
                }
            }
            RefNode::ModuleDeclaration(x) => {
                let start_keyword = unwrap_node!(x, Keyword).unwrap();
                let start_keyword = get_identifier(start_keyword).unwrap();
                let start_pos = get_position(&doc, start_keyword, 0);
                let module_range = Range { start: start_pos.clone(), end: start_pos };

                let id = unwrap_node!(x, ModuleIdentifier).unwrap();
                let id = get_identifier(id).unwrap();
                let name = syntax_tree.get_str(&id).unwrap();

                fast.new_module(name, module_range);
            }
            RefNode::ParameterDeclaration(param_dec) => {
                let mut event_iter = param_dec.into_iter().event();
                match param_dec {
                    ParameterDeclaration::Param(x) => {
                        let keyword_locate = &x.nodes.0.nodes.0;
                        // println!("keyword {:#?}", keyword_locate);
                        let start_pos = get_position(&doc, keyword_locate.clone(), 0);

                        let net_type = match unwrap_node!(RefNode::ParameterDeclarationParam(x), DataType) {
                            Some(RefNode::DataType(data_type)) => {
                                let id = unwrap_node!(data_type, SimpleIdentifier, Keyword);
                                if id == None {
                                    "wire"
                                } else {
                                    let id = get_identifier(id.unwrap()).unwrap();
                                    syntax_tree.get_str(&id).unwrap()
                                }
                            }
                            _ => "wire"
                        };

                        for (index, (name, loc, init)) in list_param_assignment(syntax_tree, &x.nodes.2, &mut event_iter).iter().enumerate() {
                            let start_pos = if index != 0 {
                                get_position(&doc, loc.clone(), 0)
                            } else {
                                start_pos.clone()
                            };
                            let end_pos = get_position(&doc, loc.clone(), loc.len);
                            let param_range = Range { start: start_pos, end: end_pos };
                            fast.add_parameter(name, net_type, init, param_range);
                        }
                    }
                    _ => ()
                }

            }
            RefNode::PortDeclaration(x) => {
                if let Some(id) = unwrap_node!(x, InputDeclaration, OutputDeclaration, InoutDeclaration) {
                    let id = get_identifier(id).unwrap();
                    let dir_type = syntax_tree.get_str(&id).unwrap();
                    let start_pos = get_position(&doc, id, 0);

                    let net_type = match unwrap_node!(x, DataType, ImplicitDataType) {
                        Some(RefNode::DataType(x)) => {
                            let id = unwrap_node!(x, Keyword);
                            if id != None {
                                syntax_tree.get_str(&get_identifier(id.unwrap()).unwrap()).unwrap()
                            } else {
                                "unknown"
                            }
                        },
                        Some(RefNode::ImplicitDataType(_)) => "wire",
                        _ => "unknown"
                    };

                    let width = match unwrap_node!(x, PackedDimensionRange) {
                        Some(RefNode::PackedDimensionRange(x)) => {
                            let port_width = sv_parser::NeedParseExpression::Port(x.clone());
                            let (width, _) = parse_expression(&syntax_tree, &port_width);
                            width
                        }
                        _ => "1".to_string()
                    };

                    if let Some(RefNode::ListOfPortIdentifiers(x)) = unwrap_node!(x, ListOfPortIdentifiers) {
                        for node in x {
                            if let RefNode::PortIdentifier(x) = node {
                                let id = unwrap_node!(x, Identifier).unwrap();
                                let id = get_identifier(id).unwrap();
                                let name = syntax_tree.get_str(&id).unwrap();
                                let port_range = Range { start: start_pos.clone(), end: get_position(&doc, id, id.len) };

                                fast.add_port(name, dir_type, net_type, width.as_str(), port_range);
                            }
                        }
                    }
                }
            }
            RefNode::AnsiPortDeclaration(x) => {
                if let Some(id) = unwrap_node!(x, PortIdentifier) {
                    let name_locate = get_identifier(id).unwrap();
                    let name = syntax_tree.get_str(&name_locate).unwrap();
                    // let character = get_column_by_offset(&content, name_locate.offset);
                    let end_pos = get_position(&doc, name_locate, name_locate.len);

                    let id = unwrap_node!(x, PortDirection);
                    let port_range = if id != None {
                        let id = id.unwrap();
                        let dir_locate = get_identifier(id).unwrap();
                        ansi_port_last_dir = syntax_tree.get_str(&dir_locate).unwrap();
                        Range { start: get_position(&doc, dir_locate, 0), end: end_pos }
                    } else {
                        Range { start: get_position(&doc, name_locate, 0), end: end_pos }
                    };

                    let net_type = if unwrap_node!(x, AnsiPortDeclarationVariable) != None {
                        "wire"
                    } else {
                        match unwrap_node!(x, DataType, ImplicitDataType) {
                            Some(RefNode::DataType(x)) => {
                                let id = unwrap_node!(x, Keyword);
                                if id != None {
                                    syntax_tree.get_str(&get_identifier(id.unwrap()).unwrap()).unwrap()
                                } else {
                                    "unknown"
                                }
                            },
                            Some(RefNode::ImplicitDataType(_)) => "wire",
                            _ => "unknown"
                        }
                    };

                    let width = match unwrap_node!(x, PackedDimensionRange) {
                        Some(RefNode::PackedDimensionRange(x)) => {
                            let port_width = sv_parser::NeedParseExpression::Port(x.clone());
                            let (width, _) = parse_expression(&syntax_tree, &port_width);
                            width
                        }
                        _ => "1".to_string()
                    };

                    fast.add_port(name, ansi_port_last_dir, net_type, width.as_str(), port_range);
                }
            }
            RefNode::ModuleInstantiation(x) => {
                if let Some(id) = unwrap_node!(x, ModuleIdentifier) {
                    let id = get_identifier(id).unwrap();
                    let inst_type = syntax_tree.get_str(&id).unwrap();
                    let start_pos = get_position(&doc, id, 0);
                    let range = get_pp_range(&doc, RefNode::ModuleInstantiation(x));
                    let inst_range = Range { start: start_pos, end: range.end };

                    if let Some(id) = unwrap_node!(x, HierarchicalInstance) {
                        let hier_node = id.clone();
                        let id = get_identifier(id).unwrap();
                        let name = syntax_tree.get_str(&id).unwrap();

                        let param_range = match unwrap_node!(x, ParameterValueAssignment) {
                            Some(inst_node) => {
                                get_pp_range(&doc, inst_node).to_option()
                            }
                            _ => None
                        };

                        let inst_param_assignments = if let Some(param_node) = unwrap_node!(x, ParameterValueAssignment) {
                            get_instance_params(syntax_tree, &doc, param_node)
                        } else {
                            Vec::<InstParameter>::new()
                        };

                        let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, hier_node.clone());
                        let port_range = get_pp_range(&doc, hier_node).to_option();

                        fast.add_instance(
                            name, inst_type, inst_range,
                            param_range, inst_param_assignments,
                            port_range, inst_port_assignments
                        );
                    }
                }
            }
            RefNode::GateInstantiation(x) => {
                let id = unwrap_node!(x, GateInstantiation).unwrap();
                let id = get_identifier(id).unwrap();
                let inst_type = syntax_tree.get_str(&id).unwrap();
                let start_pos = get_position(&doc, id, 0);
                let range = get_pp_range(&doc, RefNode::GateInstantiation(x));
                let inst_range = Range { start: start_pos, end: range.end };

                match unwrap_node!(x, NInputGateInstance, NOutputGateInstance) {
                    Some(id) => {
                        let gate_node = id.clone();
                        let id = get_identifier(id).unwrap();
                        let name = syntax_tree.get_str(&id).unwrap();

                        let param_range = None;
                        let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, gate_node.clone());
                        let port_range = get_pp_range(&doc, gate_node).to_option();

                        fast.add_instance(
                            name, inst_type, inst_range,
                            param_range, Vec::<InstParameter>::new(),
                            port_range, inst_port_assignments
                        );
                    }
                    _ => ()
                }
            }
            RefNode::Keyword(x) => {
                let id = x.nodes.0;                
                let name = syntax_tree.get_str(&id).unwrap();
                let pos = get_position(&doc, id, name.len());
                
                // 根据关键词进行特殊处理
                // 比如找到 endmodule 的位置来确定目前的这个 module 的 end
                match name {
                    "endmodule" => {
                        // 尝试获取 content 最后一个元素的可变引用，该引用如果存在，说明已经创建了一个 module
                        if let Some(last_module) = fast.content.last_mut() {
                            last_module.range.end.line = pos.line;
                            last_module.range.end.character = pos.line;
                        }
                    },
                    _ => {}
                }
            }
            _ =>  ()
        }
    }

    // update_module_range(&path, &mut hdlparam);

    Ok(fast)
}

// 获取 port 或者 param 的 range
/// 返回的四元组：(start_line, start_character, end_line, end_character)
pub fn get_pp_range(doc: &Rope, node: RefNode) -> Range {
    if let Some(locate) = get_first_last_locate(node) {
        Range {
            start: get_position(doc, locate.0, 0),
            end: get_position(doc, locate.1, locate.1.len)
        }
    } else {
        Range { start: Position { line: 0, character: 0}, end: Position { line: 0, character: 0} }
    }
}

fn get_first_last_locate(node: RefNode) -> Option<(Locate, Locate)> {
    let mut first_locate = Locate { offset: 0, line: 0, len: 0 };
    let mut last_locate = Locate { offset: 0, line: 0, len: 0 };

    for n in node {
        if let RefNode::Symbol(x) = n {
            let locate = x.nodes.0;
            if locate != last_locate { last_locate = locate; }
            if first_locate.offset == 0 { first_locate = locate; };
        }
    }

    if last_locate.offset == 0 {
        None
    } else {
        Some((first_locate, last_locate))
    }
}

pub fn get_instance_params(syntax_tree: &SyntaxTree, doc: &Rope, node: RefNode) -> Vec<InstParameter> {
    let mut parameters = Vec::new();

    for list in node {
        match unwrap_node!(list, ListOfParameterAssignmentsNamed, ListOfParameterAssignmentsOrdered) {
            Some(RefNode::ListOfParameterAssignmentsNamed(x)) => {
                for assign in x {
                    if let RefNode::NamedParameterAssignment(ident) = assign {
                        let param_range = get_pp_range(doc, assign);
                        let param_name_locate = get_identifier(RefNode::ParameterIdentifier(&(ident.nodes.1)));
                        let param_name = syntax_tree.get_str(&param_name_locate).unwrap();
                        let name = if let (_, Some(name_expr), _) = ident.nodes.2.nodes.clone() {
                            if let Some(RefNode::Expression(name_expr)) = unwrap_node!(name_expr.into_iter(), Expression) {
                                let expr = sv_parser::NeedParseExpression::Expression(name_expr.clone());
                                let (expr, _) = parse_expression(syntax_tree, &expr);
                                Some(expr)
                            } else {
                                None
                            }
                        } else {
                            None
                        };
                        let param = InstParameter {
                            parameter: Some(param_name.to_string()),
                            assign_val: name,
                            assign_type: AssignType::Named,
                            range: param_range
                        };
                        parameters.push(param);
                    };
                }
            }
            Some(RefNode::ListOfParameterAssignmentsOrdered(x)) => {
                for assign in x {
                    if let RefNode::OrderedParameterAssignment(ident) = assign {
                        let expr = ident.nodes.0.clone();
                        if let Some(RefNode::Expression(expr)) = unwrap_node!(expr.into_iter(), Expression) {
                            let start_locate = get_identifier(RefNode::Expression(expr));
                            let expr = sv_parser::NeedParseExpression::Expression(expr.clone());
                            let (expr, end_locate) = parse_expression(syntax_tree, &expr);
                            let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
                            let end_locate = end_locate.unwrap_or(start_locate);
                            let param = InstParameter {
                                parameter: None,
                                assign_val: Some(expr),
                                assign_type: AssignType::Ordered,
                                range: Range {
                                    start: get_position(doc, start_locate, 0),
                                    end: get_position(doc, end_locate, end_locate.len)
                                }
                            };
                            parameters.push(param);
                        }
                    }
                }
            }
            _ => {}
        }
    }

    parameters.sort_by_key(|p| p.range.clone());
    parameters.dedup_by_key(|p| p.range.clone());
    parameters
}

pub fn get_instance_ports(syntax_tree: &SyntaxTree, doc: &Rope, node: RefNode) -> Vec<InstPort> {
    let mut ports = Vec::new();
    for list in node {
        match unwrap_node!(list, ListOfPortConnectionsNamed, ListOfPortConnectionsOrdered, InputTerminal, OutputTerminal) {
            Some(RefNode::ListOfPortConnectionsNamed(x)) => {
                for connect in x {
                    if let RefNode::NamedPortConnectionIdentifier(ident) = connect {
                        let port_range = get_pp_range(doc, connect);
                        let port_name_locate = get_identifier(RefNode::PortIdentifier(&(ident.nodes.2)));
                        let port_name = syntax_tree.get_str(&port_name_locate).unwrap();
                        let name = if ident.nodes.3.is_some() {
                            if let (_, Some(name_expr), _) = ident.nodes.3.clone().unwrap().nodes {
                                let expr = sv_parser::NeedParseExpression::Expression(name_expr);
                                let (expr, _) = parse_expression(syntax_tree, &expr);
                                Some(expr)
                            } else {
                                None
                            }
                        } else {
                            None
                        };
                        let port = InstPort {
                            port: Some(port_name.to_string()),
                            assign_val: name,
                            assign_type: AssignType::Named,
                            range: port_range
                        };
                        ports.push(port);
                    };
                }
            }
            Some(RefNode::ListOfPortConnectionsOrdered(x)) => {
                for connect in x {
                    if let RefNode::OrderedPortConnection(ident) = connect {
                        if let Some(expr) = ident.nodes.1.clone() {
                            let start_locate = get_identifier(RefNode::Expression(&expr));
                            let expr = sv_parser::NeedParseExpression::Expression(expr);
                            let (expr, end_locate) = parse_expression(syntax_tree, &expr);
                            let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
                            let end_locate = end_locate.unwrap_or(start_locate);
                            let port = InstPort {
                                port: None,
                                assign_val: Some(expr),
                                assign_type: AssignType::Ordered,
                                range: Range {
                                    start: get_position(doc, start_locate, 0),
                                    end: get_position(doc, end_locate, end_locate.len)
                                }
                            };
                            ports.push(port);
                        }
                    };
                }
            }
            Some(RefNode::InputTerminal(x)) => {
                let expr = x.nodes.0.clone();
                let start_locate = get_identifier(RefNode::Expression(&expr));
                let expr = sv_parser::NeedParseExpression::Expression(expr);
                let (expr, end_locate) = parse_expression(syntax_tree, &expr);
                let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
                let end_locate = end_locate.unwrap_or(start_locate);
                let port = InstPort {
                    port: None,
                    assign_val: Some(expr),
                    assign_type: AssignType::Ordered,
                    range: Range {
                        start: get_position(doc, start_locate, 0),
                        end: get_position(doc, end_locate, end_locate.len)
                    }
                };
                ports.push(port);
            }
            Some(RefNode::OutputTerminal(x)) => {
                let expr = x.nodes.0.clone();
                let start_locate = get_identifier(RefNode::NetLvalue(&expr));
                let expr = sv_parser::NeedParseExpression::NetValue(expr);
                let (expr, end_locate) = parse_expression(syntax_tree, &expr);
                let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
                let end_locate = end_locate.unwrap_or(start_locate);
                let port = InstPort {
                    port: None,
                    assign_val: Some(expr),
                    assign_type: AssignType::Ordered,
                    range: Range {
                        start: get_position(doc, start_locate, 0),
                        end: get_position(doc, end_locate, end_locate.len)
                    }
                };
                ports.push(port);
            }
            _ => ()
        }
    }

    ports.sort_by_key(|p| p.range.clone());
    ports.dedup_by_key(|p| p.range.clone());
    ports
}

fn parse_expression(syntax_tree: &SyntaxTree, x: &sv_parser::NeedParseExpression) -> (String, Option<Locate>) {
    let mut last_locate = Locate { offset: 0, line: 0, len: 0 };
    let mut expression = String::new();

    for node in x {
        // println!("parse expression::node {:#?}", node);
        match unwrap_node!(node, SimpleIdentifier, Symbol, UnsignedNumber, HexNumber, OctalNumber, BinaryNumber) {
            Some(RefNode::SimpleIdentifier(x)) => {
                let locate = x.nodes.0;
                if locate != last_locate {
                    last_locate = locate;
                    let s = syntax_tree.get_str(&locate).unwrap();
                    expression = expression + s;
                    // println!("parse expression {}", s);
                }
            }
            Some(RefNode::Symbol(x)) => {
                let locate = x.nodes.0;
                if locate != last_locate {
                    last_locate = locate;
                    let s = syntax_tree.get_str(&x.nodes.0).unwrap();
                    expression = expression + s;
                    // println!("parse expression {}", s);
                }
            }
            Some(RefNode::UnsignedNumber(x)) => {
                let locate = x.nodes.0;
                if locate != last_locate {
                    last_locate = locate;
                    let s = syntax_tree.get_str(&x.nodes.0).unwrap();
                    expression = expression + s;
                    // println!("parse expression {}", s);
                }
            }
            Some(RefNode::HexNumber(x)) => {
                let locate = x.nodes.1.nodes.0;
                if locate != last_locate {
                    last_locate = locate;
                    let size = if x.nodes.0 != None { syntax_tree.get_str(&x.nodes.0).unwrap() } else { "" };
                    let base = syntax_tree.get_str(&x.nodes.1.nodes.0).unwrap();
                    let number = syntax_tree.get_str(&x.nodes.2.nodes.0).unwrap();
                    expression = expression + size + base + number;
                    // println!("parse expression {}", expression);
                }
            }
            Some(RefNode::OctalNumber(x)) => {
                let locate = x.nodes.1.nodes.0;
                if locate != last_locate {
                    last_locate = locate;
                    let size = if x.nodes.0 != None { syntax_tree.get_str(&x.nodes.0).unwrap() } else { "" };
                    let base = syntax_tree.get_str(&x.nodes.1.nodes.0).unwrap();
                    let number = syntax_tree.get_str(&x.nodes.2.nodes.0).unwrap();
                    expression = expression + size + base + number;
                    // println!("parse expression {}", expression);
                }
            }
            Some(RefNode::BinaryNumber(x)) => {
                let locate = x.nodes.1.nodes.0;
                if locate != last_locate {
                    last_locate = locate;
                    let size = if x.nodes.0 != None { syntax_tree.get_str(&x.nodes.0).unwrap() } else { "" };
                    let base = syntax_tree.get_str(&x.nodes.1.nodes.0).unwrap();
                    let number = syntax_tree.get_str(&x.nodes.2.nodes.0).unwrap();
                    expression = expression + size + base + number;
                    // println!("parse expression {}", expression);
                }
            }
            _ => ()
        }
    }
    if expression == "" {
        ("unknown".to_string(), None)
    } else {
        // println!("parse function lastlocate {:?}", last_locate);
        (expression, Some(last_locate))
    }
} 
      
pub fn get_identifier(node: RefNode) -> Option<Locate> {
    // unwrap_node! can take multiple types
    match unwrap_node!(node, SimpleIdentifier, EscapedIdentifier, Keyword) {
        Some(RefNode::SimpleIdentifier(x)) => {
            return Some(x.nodes.0);
        }
        Some(RefNode::EscapedIdentifier(x)) => {
            return Some(x.nodes.0);
        }
        Some(RefNode::Keyword(x)) => {
            return Some(x.nodes.0);
        }
        _ => None,
    }
}

pub fn get_position(doc: &Rope, locate: Locate, offset: usize) -> Position {
    let byte = locate.offset + offset;
    let pos = doc.byte_to_pos(byte);
    hdlparam::Position::from_lsp_position(&pos)
}

fn get_includes(path: &PathBuf) -> Vec<crate::core::hdlparam::Include> {
    let mut includes = Vec::new();

    let file = File::open(path).unwrap();
    let reader = BufReader::new(file);

    for (line_number, line_content) in reader.lines().enumerate() {
        let line_content = match line_content {
            Ok(content) => content,
            Err(e) => {
                println!("line {} has error {}", line_number, e);
                "".to_string()
            }
        };

        if line_content.trim().starts_with("`include") {

            let parts: Vec<&str> = line_content.split_whitespace().collect();

            if parts.len() >= 2 {
                let mut path = parts[1].trim();
                if path.starts_with("\"") {
                    path = path.strip_prefix("\"").unwrap();
                }
                if path.ends_with("\"") {
                    path = path.strip_suffix("\"").unwrap();
                }

                let last_character = line_content.find(path).unwrap() + path.len();

                includes.push(crate::core::hdlparam::Include {
                    path: path.to_string(),
                    range: crate::core::hdlparam::Range {
                        start: crate::core::hdlparam::Position {
                            line: (line_number + 1) as u32, character: 1
                        },
                        end: crate::core::hdlparam::Position {
                            line: (line_number + 1) as u32, character: last_character as u32
                        }
                    }
                });
            }
        }
    }

    includes
}

#[allow(unused)]
fn update_module_range(path: &PathBuf, fast: &mut FastHdlparam) {
    let file = File::open(path).unwrap();
    let reader = BufReader::new(file);

    let re_module = Regex::new(r"^\s*module\s+(\w+)\s*\(").unwrap();
    let re_endmodule = Regex::new(r"^\s*endmodule\s*$").unwrap();

    let mut current_offset = 0;
    let mut module_stack: Vec<String> = Vec::new();

    for (line_number, line_content) in reader.lines().enumerate() {
        match line_content {
            Ok(line) => {
                let line_length = line.len() + 1; // +1 for newline character
                current_offset += line_length;
                if let Some(captures) = re_module.captures(&line) {
                    let module_name = captures.get(1).unwrap().as_str().to_string();
                    module_stack.push(module_name.clone());
                } else if re_endmodule.is_match(&line) {
                    if let Some(module_name) = module_stack.pop() {
                        fast.update_module_range(&module_name, (line_number + 1) as u32, current_offset as u32);
                        // println!("Module {} ends.", module_name);
                    }
                }
            }
            _ => ()
        }
    }
}

fn param_assignment(
    tree: &SyntaxTree,
    _: &ParamAssignment,
    event_iter: &mut EventIter,
) -> Option<(String, Locate, String)> {
    if let Some(param_assign) =
        skip_until_enter!(tree, event_iter, RefNode::ParamAssignment, &ParamAssignment) {
        let ident = get_ident(tree, RefNode::ParameterIdentifier(&param_assign.nodes.0));
        let mut type_str = String::new();
        advance_until_leave!(type_str, tree, event_iter, RefNode::ParamAssignment);
        let parts: Vec<&str> = type_str.split_whitespace().collect();
        type_str = if let Some(last_part) = parts.last() {
            last_part.to_string()
        } else {
            "unknown".to_string()
        };
        Some((ident.0, ident.1, type_str))
    } else {
        None
    }
}

fn list_param_assignment(
    tree: &SyntaxTree,
    _: &ListOfParamAssignments,
    event_iter: &mut EventIter,
) -> Vec<(String, Locate, String)>{
    let mut params = Vec::new();
    // let mut defs: Vec<GenericDec> = Vec::new();
    if let Some(p_a_list) = skip_until_enter!(
        tree,
        event_iter,
        RefNode::ListOfParamAssignments,
        &ListOfParamAssignments
    ) {
        for param_assign in p_a_list.nodes.0.contents() {
            if let Some(assignment) = param_assignment(tree, param_assign, event_iter) {
                params.push(assignment);
            }
        }
    };
    params
}

/// 找到 node 的 名字，开始的位置和结束的位置
pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, Locate) {
    let loc = unwrap_locate!(node).unwrap();
    let ident_str = tree.get_str(loc).unwrap().to_string();

    (ident_str, *loc)
}

#[cfg(test)]
mod tests {
    use std::{fs, path::Path};
    use super::sv_parser;

    const TESTFILES_DIR: &str = "/home/dide/project/digital-lsp-server/testfiles";
    const DIGTIAL_IDE_TEST: &str = "/home/dide/project/Digital-Test/Digital-IDE-test/user";

    macro_rules! unwrap_result {
        ($expr:expr) => {
            match $expr {
                Ok(e) => e,
                Err(_) => return
            }
        };
    }

    macro_rules! unwrap_option {
        ($expr:expr) => {
            match $expr {
                Some(e) => e,
                None => return
            }
        };
    }

    #[test]
    fn test_sv_parse() {
        let entries = unwrap_result!(fs::read_dir(TESTFILES_DIR));
        for entry in entries {
            let entry = unwrap_result!(entry);
            let file_path = entry.path();
            if file_path.is_file() {
                let extension = unwrap_option!(file_path.extension());
                let file_path = unwrap_option!(file_path.to_str());
                if extension == "v" || extension == "sv" {
                    let _ = sv_parser(file_path);
                }
            }
        }
    }

    #[test]
    fn test_digital_ide_test() {
        // 判断路径是否存在且为文件夹
        let path = Path::new(DIGTIAL_IDE_TEST);
        if path.exists() && path.is_dir() {
            // 递归遍历文件夹
            if let Err(e) = traverse_directory(path) {
                eprintln!("Error: {}", e);
            }
        } else {
            eprintln!("Path does not exist or is not a directory");
        }
    }

    fn traverse_directory(dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
    
                if path.is_dir() {
                    // 递归遍历子文件夹
                    traverse_directory(&path)?;
                } else if path.is_file() {
                    // 检查文件扩展名
                    if let Some(ext) = path.extension() {
                        if ext == "v" || ext == "sv" {
                            println!("Test file: {:?}", path);
                            // TODO: Check Stack Overflow tests
                            if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/comp1001.sv" {
                                continue;
                            }
                            if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/comp1000.sv" {
                                continue;
                            }
                            if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/br_gh330.sv" {
                                continue;
                            }
                            if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/hdlconv/pri_encoder_using_assign.sv" {
                                continue;
                            }
                            let file_path = path.to_str().unwrap();
                            let _ = sv_parser(file_path);
                        }
                    }
                }
            }
        }
        Ok(())
    }
}