use std::{fmt::Debug, fs::{self, File}, io::{Read, Write}, path::PathBuf, str::FromStr, time::UNIX_EPOCH};

use log::info;
use ropey::Rope;
use serde::{Deserialize, Serialize};
use tower_lsp::lsp_types::*;

use crate::sources::LSPSupport;

use super::to_escape_path;

#[allow(unused)]
pub fn get_range_text(path: &PathBuf, range: &Range) -> Option<String> {
    let path = to_escape_path(path);
    if let Some(rope) = open_doc_as_rope(&path) {
        let start_index = rope.pos_to_byte(&range.start);
        let end_index = rope.pos_to_byte(&range.end);
        info!("start index: {}, end index: {}", start_index, end_index);
        return Some(rope.slice(start_index..end_index).to_string());
    }
    None
}

#[allow(unused)]
pub fn open_doc_as_rope(path: &PathBuf) -> Option<Rope> {
    if let std::result::Result::Ok(text) = fs::read_to_string(path) {
        let rope = Rope::from_str(text.as_str());
        Some(rope)
    } else {
        None
    }
}

pub struct RecursiveFileIterator {
    stack: Vec<PathBuf>,
}

/// 递归获取所有文件
impl RecursiveFileIterator {
    #[allow(unused)]
    pub fn new(start_dir: &str) -> Self {
        let start_dir = PathBuf::from_str(start_dir).unwrap();
        RecursiveFileIterator {
            stack: vec![start_dir],
        }
    }
}

impl Iterator for RecursiveFileIterator {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(path) = self.stack.pop() {
            if path.is_dir() {
                if let Ok(entries) = fs::read_dir(path) {
                    for entry in entries.flatten() {
                        self.stack.push(entry.path());
                    }
                }
            } else {
                return Some(path);
            }
        }
        None
    }
}


/// 计算文件大小，单位 KB
pub fn file_size_in_kb(path: &str) -> Result<u64, std::io::Error> {
    // 获取文件元数据
    let metadata = fs::metadata(path)?;
    
    // 获取文件大小（以字节为单位）
    let file_size_bytes = metadata.len();
    
    // 将文件大小转换为 KB，并确保结果在 u32 范围内
    let file_size_kb = (file_size_bytes / 1024) as u64;
    
    Ok(file_size_kb)
}

pub fn get_last_modified_time(path: &str) -> Result<u64, std::io::Error> {
    // 获取文件元数据
    let metadata = fs::metadata(path)?;
    
    // 获取文件的最近修改时间
    let modified_time = metadata.modified()?;

    let duration = modified_time.duration_since(UNIX_EPOCH).map_err(
        |e| std::io::Error::new(std::io::ErrorKind::Other, e)
    )?;

    let seconds = duration.as_secs();
    
    Ok(seconds)
}

/// 序列化结构体到二进制文件
pub fn k_serialize<T>(path: &PathBuf, data: T) -> Result<(), std::io::Error>
where T: Serialize + Debug {
    let buffer: Vec<u8> = bincode::serialize(&data).unwrap();
    match File::create(path) {
        Ok(mut file) => {
            match file.write_all(&buffer) {
                Ok(_) => Ok(()),
                Err(err) => Err(err)
            }
        }
        Err(err) => Err(err)
    }
}

/// 反序列化二进制文件到结构体
pub fn k_deserialize<T>(path: &PathBuf) -> Result<T, std::io::Error>
where T: for<'de> Deserialize<'de> + Debug {
    match File::open(path) {
        Ok(mut file) => {
            let mut buffer = Vec::<u8>::new();
            match file.read_to_end(&mut buffer) {
                Ok(_) => {
                    let meta_map: Result<T, Box<bincode::ErrorKind>> = bincode::deserialize(&buffer);
                    if meta_map.is_ok() {
                        Ok(meta_map.unwrap())
                    } else {
                        let err: Box<bincode::ErrorKind> = meta_map.unwrap_err();
                        info!("error happen when deserialize index.cache from \"{path:?}\": {err:?}");
                        Err(std::io::Error::new(std::io::ErrorKind::InvalidData, err))
                    }
                }
                Err(err) => {
                    info!("error happen when load bytes to buffer from \"{path:?}\": {err:?}");
                    Err(err)
                }
            }
        }
        Err(err) => {
            info!("error happen when read index.cache from \"{path:?}\": {err:?}");
            Err(err)
        }
    }
}