use std::collections::HashMap;
use std::sync::RwLock;

use log::info;
use serde::{Deserialize, Serialize};
use tower_lsp::lsp_types::Position as LspPosition;
use tower_lsp::lsp_types::Range as LspRange;

use crate::sources::AstLike;

#[derive(Debug, Clone, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize)]
pub struct Position {
    pub line: u32,
    pub character: u32
}

impl Position {
    #[allow(unused)]
    pub fn to_lsp_position(&self) -> LspPosition {
        LspPosition { line: self.line, character: self.character }
    }

    pub fn from_lsp_position(pos: &LspPosition) -> Position {
        Position { line: pos.line, character: pos.character }
    }

    pub fn new(line: u32, character: u32) -> Position {
        Position {
            line, character
        }
    }
}

#[derive(Debug, Clone, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize)]
pub struct Range {
    pub start: Position,
    pub end: Position
}


impl Range {
    #[allow(unused)]
    pub fn to_lsp_range(&self) -> LspRange {
        let start_pos = self.start.to_lsp_position();
        let end_pos=  self.end.to_lsp_position();
        LspRange::new(start_pos, end_pos)
    }

    #[allow(unused)]
    pub fn from_lsp_range(range: &LspRange) -> Range {
        Range {
            start: Position {
                line: range.start.line,
                character: range.start.character
            },
            end: Position {
                line: range.end.line,
                character: range.end.character
            }
        }
    }

    /// 判断输入的 position 是否在当前 range 内
    pub fn contains(&self, postion: &LspPosition) -> bool {
        compare_pos(&self.start.to_lsp_position(), postion) != 1 && compare_pos(postion, &self.end.to_lsp_position()) != 1
    }

    #[allow(unused)]
    pub fn before(&self, range: &Range) -> bool {
        let current_pos = &self.end.to_lsp_position();
        let target_pos = &range.start.to_lsp_position();
        compare_pos(current_pos, target_pos) != 1
    }

    #[allow(unused)]
    pub fn after(&self, range: &Range) -> bool {
        let current_pos = &self.start.to_lsp_position();
        let target_pos = &range.end.to_lsp_position();
        compare_pos(current_pos, target_pos) != -1
    }

    /// 对所有的 line 或者 所有的 character 进行偏移操作
    pub fn affine(&mut self, line_offset: i32, character_offset: i32) -> &Range {
        if line_offset > 0 {
            self.start.line += line_offset as u32;
            self.end.line += line_offset as u32;
        } else {
            self.start.line -= (- line_offset) as u32;
            self.end.line -= (- line_offset) as u32;
        }

        if character_offset > 0 {
            self.start.character += character_offset as u32;
            self.end.character += character_offset as u32;
        } else {
            self.start.character -= (- character_offset) as u32;
            self.end.character -= (- character_offset) as u32;
        }
        
        self
    }

    pub fn is_empty(&self) -> bool {
        self.start.line == 0 && self.start.character == 0 && self.end.line == 0 && self.end.character == 0
    }

    pub fn to_option(&self) -> Option<Range> {
        if self.is_empty() {
            None
        } else {
            Some(self.clone())
        }
    }

    pub fn default() -> Range {
        Range {
            start: Position::new(0, 0),
            end: Position::new(0, 0)
        }
    }
}

/// 比较两个 pos 的位置关系
/// 1：pos1 在 pos2 后面
/// 0：pos1 和 pos2 一样
/// -1：pos1 在 pos2 前面 
fn compare_pos(pos1: &LspPosition, pos2: &LspPosition) -> i32 {
    if pos1.line > pos2.line {
        1
    } else if pos1.line < pos2.line {
        -1
    } else if pos1.character > pos2.character {
        1
    } else if pos1.character < pos2.character {
        -1
    } else {
        0
    }
}

#[derive(Debug, Serialize, PartialEq, Deserialize, Clone)]
pub struct Port {
    pub name: String,
    #[serde(rename = "type")]
    pub dir_type: String,
    pub net_type: String,
    pub width: String,
    pub signed: String,
    pub range: Range
}

#[derive(Debug, Serialize, PartialEq, Deserialize, Clone)]
pub struct Parameter {
    pub name: String,
    pub net_type: String,
    pub init: String,
    pub range: Range
}

impl Port {
    pub fn to_vlog_description(&self) -> String {
        let mut port_desc_array = Vec::<String>::new();
        let dir_type = match self.dir_type.as_str() {
            "in" => "input",
            "out" => "output",
            _ => &self.dir_type
        };

        port_desc_array.push(dir_type.to_string());
        if self.net_type != "unknown" {
            port_desc_array.push(self.net_type.to_string());
        }
    
        if self.signed != "unsigned" {
            port_desc_array.push("signed".to_string());
        }
    
        if self.width != "1" {
            port_desc_array.push(self.width.to_string());
        }
    
        port_desc_array.push(self.name.to_string());
        let port_desc = port_desc_array.join(" ");
        port_desc
    }
    pub fn to_vhdl_description(&self) -> String {
        let mut port_desc_array = Vec::<String>::new();

        port_desc_array.push(self.name.to_string());
        port_desc_array.push(":".to_string());
        port_desc_array.push(self.dir_type.to_string());
        let width_string = self.width.replace("[", "(").replace("]", ")").replace(":", " downto ");
        port_desc_array.push(format!("{}{};", self.net_type.to_lowercase(), width_string));

        let port_desc = port_desc_array.join(" ");
        port_desc
    }
}

impl Parameter {
    pub fn to_vlog_description(&self) -> String {
        let mut param_desc_array = Vec::<String>::new();
        param_desc_array.push(format!("parameter {}", self.name));
    
        if self.init != "unknown" {
            param_desc_array.push("=".to_string());
            param_desc_array.push(self.init.to_string());
        }
        let param_desc = param_desc_array.join(" ");
        param_desc
    }
    pub fn to_vhdl_description(&self) -> String {
        let mut param_desc_array = Vec::<String>::new();
        param_desc_array.push(format!("{} : {}", self.name, self.net_type.to_lowercase()));
    
        if self.init != "unknown" {
            param_desc_array.push(format!(" := {}", self.init));
        }
        let param_desc = param_desc_array.join(" ");
        param_desc
    }
}

#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
pub enum AssignType {
    Named,
    Ordered
}

#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
pub struct InstPort {
    pub port: Option<String>,
    pub assign_val: Option<String>,
    pub assign_type: AssignType,
    pub range: Range
}

#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
pub struct InstParameter {
    pub parameter: Option<String>,
    pub assign_val: Option<String>,
    pub assign_type: AssignType,
    pub range: Range
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Instance {
    pub name: String,
    #[serde(rename = "type")]
    pub inst_type: String,
    pub instparams: Option<Range>,
    pub intstparam_assignments: Vec<InstParameter>,
    pub instports: Option<Range>,
    pub intstport_assignments: Vec<InstPort>,
    pub range: Range
}

impl Instance {
    pub fn gen_dot_completion_port_range(&self) -> Range {
        // TODO: 精心调制这个方法
        if let Some(port_range) = &self.instports {
            let mut new_port_range = port_range.clone();

            info!("get port range: {new_port_range:?}, instance: {self:?}");

            if let Some(param_range) = &self.instparams {
                new_port_range.start.line = param_range.end.line - 1;
                new_port_range.start.character = param_range.end.character;
            } else {
                new_port_range.start.line = self.range.start.line;
                new_port_range.start.character = self.range.start.character + 1;
            }

            new_port_range.end.line += 1;
            new_port_range.affine(-1, -1);
            return new_port_range;
        }

        self.range.clone()
    }

    #[allow(unused)]
    pub fn gen_dot_completion_param_range(&self) -> Range {
        // TODO: 精心调制这个方法
        if let Some(param_range) = &self.instparams {
            let mut new_param_range = param_range.clone();
            new_param_range.start.line = self.range.start.line;
            new_param_range.start.character = self.range.start.character + 1;
            new_param_range.end.line += 1;
            return new_param_range;
        }

        self.range.clone()
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Module {
    pub name: String,
    #[serde(rename = "archName")]
    pub arch_name: String,
    pub params: Vec<Parameter>,
    pub ports: Vec<Port>,
    pub instances: Vec<Instance>,
    pub range: Range
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct DefineParam {
    pub name: String,
    pub value: String
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Define {
    /// 宏的名字
    /// <code>`define {name} {replacement}</code>
    pub name: String,
    /// 宏的名字
    /// <code>`define {name} {replacement}</code>
    pub replacement: String,
    /// 宏的范围
    pub range: Range,
    /// 宏的参数（如果为函数宏才会有这个选项）
    /// <code>`define {name} {replacement}({...params})</code>
    pub params: Vec<DefineParam>
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Include {
    pub path: String,
    pub range: Range
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Error {
    severity: String,
    message: String,
    source: String,
    range: Position,
    running_mode: Option<String>,
    running_phase: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Macro {
    pub defines: Vec<Define>,
    pub includes: Vec<Include>,
    pub errors: Vec<Error>,
    pub invalid: Vec<Range>
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct FastHdlparam {
    #[serde(rename = "macro")]
    pub fast_macro: Macro,
    #[serde(rename = "fileType")]
    pub file_type: String,
    pub content: Vec<Module>
}

impl FastHdlparam {
    pub fn add_define(&mut self, name: &str, replacement: &str, range: Range, params: Vec<DefineParam>) {
        let define = Define {
            name: name.to_string(),
            replacement: replacement.to_string(),
            range,
            params
        };
        self.fast_macro.defines.push(define);
    }

    pub fn new_module(&mut self, name: &str, range: Range) {
        let module = Module {
            name: name.to_string(),
            arch_name: "".to_string(),
            params: Vec::new(),
            ports: Vec::new(),
            instances: Vec::new(),
            range
        };
        self.content.push(module);
    }

    pub fn new_vhdl_module(&mut self, name: String, arch_name: String, range: Range) {
        let module = Module {
            name,
            arch_name,
            params: Vec::new(),
            ports: Vec::new(),
            instances: Vec::new(),
            range
        };
        self.content.push(module);
    }

    pub fn update_module_range(&mut self, name: &str, end_line: u32, end_character: u32) {
        if let Some(matched_module) = self.content.iter_mut().find(|module| module.name == name) {
            matched_module.range.end.line = end_line;
            matched_module.range.end.character = end_character;
        }
    }

    pub fn add_parameter(&mut self, name: &str, net_type: &str, init: &str, range: Range) {
        if let Some(last_module) = self.content.last_mut() {
            let parameter = Parameter {
                name: name.to_string(),
                net_type: net_type.to_string(),
                init: init.to_string(),
                range
            };
            last_module.params.push(parameter);
            last_module.params.dedup();
        }
    }

    pub fn add_port(&mut self, name: &str, dir_type: &str, net_type: &str, width: &str, range: Range) {
        if let Some(last_module) = self.content.last_mut() {
            let port = Port {
                name: name.to_string(),
                dir_type: dir_type.to_string(),
                net_type: net_type.to_string(),
                width: width.to_string(),
                signed: "unsigned".to_string(),
                range
            };
            last_module.ports.push(port);
            last_module.ports.dedup();
        }
    }

    pub fn add_instance(&mut self, name: &str, inst_type: &str, range: Range,
        param_range: Option<Range>, params_assign: Vec<InstParameter>, port_range: Option<Range>, ports_assign: Vec<InstPort>) {
        if let Some(last_module) = self.content.last_mut() {
            let instance = Instance {
                name: name.to_string(),
                inst_type: inst_type.to_string(),
                instparams: param_range,
                intstparam_assignments: params_assign,
                instports: port_range,
                intstport_assignments: ports_assign,
                range
            };
            last_module.instances.push(instance);
        }
    }
}

pub struct HdlFile {
    /// 专注于模块树构建和粗粒度 AST 信息的数据结构
    pub fast: FastHdlparam,
    /// 名字到 module 映射的 map
    pub name_to_module: HashMap<String, Module>,
    /// 解析器生成的额外信息
    pub parse_result: sv_parser::common::ParseResult,
    /// 解析器生成的 AST 或者类似 AST 的数据结构
    pub ast_like: Option<AstLike>
}

pub struct HdlParam {
    /// 路径到 HdlFile 的映射
    pub path_to_hdl_file: RwLock<HashMap<String, HdlFile>>,
    /// 模块名字到其所在的 HdlFile 路径的映射
    pub module_name_to_path: RwLock<HashMap<String, String>>,
}



impl HdlParam {
    pub fn new() -> Self {
        Self {
            path_to_hdl_file: RwLock::new(HashMap::<String, HdlFile>::new()),
            module_name_to_path: RwLock::new(HashMap::<String, String>::new())
        }
    }

    /// 根据 path 更新 fast 和 parse_result
    pub fn update_hdl_file(
        &self,
        path: String,
        fast: FastHdlparam,
        parse_result: sv_parser::common::ParseResult,
        ast_like: Option<AstLike>
    ) {
        let mut fast_map = self.path_to_hdl_file.write().unwrap();
        // 构建映射
        let mut name_to_module = HashMap::<String, Module>::new();
        let mut module_name_to_path = self.module_name_to_path.write().unwrap();

        for module in &fast.content {
            name_to_module.insert(module.name.to_string(), module.clone());
            if !module_name_to_path.contains_key(&module.name) {
                module_name_to_path.insert(module.name.to_string(), path.to_string());
            }
        }

        let file = HdlFile { fast, name_to_module, parse_result, ast_like };
        fast_map.insert(path, file);
    }

    /// 根据 module 的名字，找到 module 对象，拷贝返回
    pub fn find_module_by_name(&self, name: &str) -> Option<Module> {
        let module_name_to_path = self.module_name_to_path.read().unwrap();
        if let Some(path) = module_name_to_path.get(name) {
            let fast_map = self.path_to_hdl_file.read().unwrap();
            if let Some(hdl_file) = fast_map.get(path) {
                if let Some(module) = hdl_file.name_to_module.get(name) {    
                    return Some(module.clone());
                }
            }            
        }

        None
    }

    /// 相比于 find_module_by_name，该方法会返回更多有关 该 module 的必要上下文，
    /// 避免重复获取锁，提升性能
    /// 返回三元组 （module, file_type, def_path）
    pub fn find_module_context_by_name(&self, name: &str) -> Option<(Module, String, String)> {
        // 获取 module_name_to_path 的读锁并查找路径
        let module_name_to_path = self.module_name_to_path.read().unwrap();
        if let Some(path) = module_name_to_path.get(name) {
            // 获取 path_to_hdl_file 的读锁并查找 HdlFile
            let fast_map = self.path_to_hdl_file.read().unwrap();
            if let Some(hdl_file) = fast_map.get(path) {
                // 查找模块
                if let Some(module) = hdl_file.name_to_module.get(name) {
                    return Some((
                        module.clone(),
                        hdl_file.fast.file_type.to_string(),
                        path.to_string()
                    ));
                }
            }
        }
    
        None
    }

    /// 根据 module name 计算出对应的 file type，默认为 common
    pub fn find_file_type_by_module_name(&self, module_name: &str) -> String {
        if let Some((_, file_type, _)) = self.find_module_context_by_name(module_name) {
            return file_type;
        }
        "common".to_string()
    }

    /// 输入 module 名字，找到 module 定义的文件的路径
    pub fn find_module_definition_path(&self, module_name: &str) -> Option<String> {
        let module_name_to_path = self.module_name_to_path.read().unwrap();
        if let Some(path) = module_name_to_path.get(module_name) {
            return Some(path.to_string());         
        }
        
        None
    }

    /// 遍历 path_string 下的所有 module，并根据条件返回
    pub fn walk_module(&self, path_string: &str, condition: impl Fn(&Module) -> bool) -> Option<Module> {
        let path_to_hdl_file = self.path_to_hdl_file.read().unwrap();
        if let Some(hdl_file) = path_to_hdl_file.get(path_string) {
            for def_module in &hdl_file.fast.content {
                if condition(def_module) {
                    return Some(def_module.clone());
                }
            }
        }
        None
    }
    
    /// 遍历 path_string 下的所有 instance，并根据条件返回
    pub fn walk_instantiation(&self, path_string: &str, condition: impl Fn(&Module, &Instance) -> bool) -> Option<Instance> {
        let path_to_hdl_file = self.path_to_hdl_file.read().unwrap();
        if let Some(hdl_file) = path_to_hdl_file.get(path_string) {
            for def_module in &hdl_file.fast.content {
                for inst in &def_module.instances {
                    if condition(def_module, inst) {
                        return Some(inst.clone());
                    }
                }
            }
        }
        None
    }

    /// 跟随一个路径进行删除
    pub fn delete_file(&self, path_string: &str) {
        let mut path_to_hdl_file = self.path_to_hdl_file.write().unwrap();
        if let Some(hdl_file) = path_to_hdl_file.get(path_string) {
            // 根据 hdl_file.fast.content 删除 self.module_name_to_path
            let mut module_name_to_path = self.module_name_to_path.write().unwrap();
            for module_info in &hdl_file.fast.content {
                module_name_to_path.remove(&module_info.name);
            }
        }
        path_to_hdl_file.remove(path_string);
        // TODO: 引入前端的 solve unhandled instance 机制
    }
    
}