use objc2_foundation::NSString;
use objc2_fs_kit::{
    FSFileSystem, FSVolume, FSItem,
    FSVolumeOperations, FSVolumeReadWriteOperations,
};
use rusqlite::Connection;
use std::sync::Mutex;

pub struct MarkBaseFS {
    sqlite: Mutex<Connection>,
    user_id: String,
}

impl MarkBaseFS {
    pub fn new(user_id: &str, db_path: &str) -> Self {
        let conn = Connection::open(db_path)
            .expect("Failed to open SQLite database");
        
        Self {
            sqlite: Mutex::new(conn),
            user_id: user_id.to_string(),
        }
    }
    
    pub fn query_node(&self, node_id: &str) -> Option<FileNodeData> {
        let conn = self.sqlite.lock().unwrap();
        
        conn.query_row(
            "SELECT node_id, label, node_type, file_size, aliases_json 
             FROM file_nodes WHERE node_id = ?",
            [node_id],
            |row| {
                Ok(FileNodeData {
                    node_id: row.get::<_, String>(0)?,
                    label: row.get::<_, String>(1)?,
                    node_type: row.get::<_, String>(2)?,
                    file_size: row.get::<_, Option<i64>>(3)?,
                    aliases_json: row.get::<_, String>(4)?,
                })
            },
        ).ok()
    }
    
    pub fn query_children(&self, parent_id: &str) -> Vec<FileNodeData> {
        let conn = self.sqlite.lock().unwrap();
        
        let mut stmt = conn.prepare(
            "SELECT node_id, label, node_type, file_size, aliases_json 
             FROM file_nodes WHERE parent_id = ?
             ORDER BY sort_order, label"
        ).unwrap();
        
        stmt.query_map([parent_id], |row| {
            Ok(FileNodeData {
                node_id: row.get::<_, String>(0)?,
                label: row.get::<_, String>(1)?,
                node_type: row.get::<_, String>(2)?,
                file_size: row.get::<_, Option<i64>>(3)?,
                aliases_json: row.get::<_, String>(4)?,
            })
        }).unwrap()
        .filter_map(|r| r.ok())
        .collect()
    }
    
    pub fn read_file(&self, node_id: &str) -> Option<Vec<u8>> {
        let conn = self.sqlite.lock().unwrap();
        
        let aliases_json: String = conn.query_row(
            "SELECT aliases_json FROM file_nodes WHERE node_id = ?",
            [node_id],
            |row| row.get(0),
        ).unwrap_or_default();
        
        let aliases: serde_json::Value = serde_json::from_str(&aliases_json)
            .unwrap_or(serde_json::json!({}));
        
        let file_path = aliases["path"].as_str().unwrap_or_default();
        
        if file_path.is_empty() {
            None
        } else {
            std::fs::read(file_path).ok()
        }
    }
}

#[derive(Debug)]
pub struct FileNodeData {
    pub node_id: String,
    pub label: String,
    pub node_type: String,
    pub file_size: Option<i64>,
    pub aliases_json: String,
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_markbase_fs_creation() {
        let fs = MarkBaseFS::new("test", "data/users/test.sqlite");
        assert_eq!(fs.user_id, "test");
    }
    
    #[test]
    fn test_file_node_data() {
        let node = FileNodeData {
            node_id: "test123".to_string(),
            label: "test.txt".to_string(),
            node_type: "file".to_string(),
            file_size: Some(1024),
            aliases_json: "{}".to_string(),
        };
        
        assert_eq!(node.node_id, "test123");
        assert_eq!(node.label, "test.txt");
    }
}

#[cfg(test)]
mod warren_tests {
    use super::*;
    
    #[test]
    fn test_warren_database_connection() {
        let fs = MarkBaseFS::new("warren", "data/users/warren.sqlite");
        assert_eq!(fs.user_id, "warren");
        
        let conn = fs.sqlite.lock().unwrap();
        let count: i64 = conn.query_row(
            "SELECT COUNT(*) FROM file_nodes",
            [],
            |row| row.get(0)
        ).unwrap();
        
        assert_eq!(count, 12659);
    }
    
    #[test]
    fn test_warren_query_root() {
        let fs = MarkBaseFS::new("warren", "data/users/warren.sqlite");
        
        let root_id: String = {
            let conn = fs.sqlite.lock().unwrap();
            conn.query_row(
                "SELECT node_id FROM file_nodes WHERE parent_id IS NULL LIMIT 1",
                [],
                |row| row.get(0)
            ).unwrap()
        };
        
        let root = fs.query_node(&root_id);
        assert!(root.is_some());
        
        let root_node = root.unwrap();
        assert_eq!(root_node.node_type, "folder");
        println!("Root node: {} - {}", root_node.node_id, root_node.label);
    }
    
    #[test]
    fn test_warren_query_children() {
        let fs = MarkBaseFS::new("warren", "data/users/warren.sqlite");
        
        let root_id: String = {
            let conn = fs.sqlite.lock().unwrap();
            conn.query_row(
                "SELECT node_id FROM file_nodes WHERE parent_id IS NULL LIMIT 1",
                [],
                |row| row.get(0)
            ).unwrap()
        };
        
        let children = fs.query_children(&root_id);
        
        assert!(children.len() > 0);
        
        let folders = children.iter().filter(|c| c.node_type == "folder").count();
        let files = children.iter().filter(|c| c.node_type == "file").count();
        
        println!("Root children: {} folders, {} files", folders, files);
        
        assert!(folders > 0);
    }
    
    #[test]
    fn test_warren_read_text_file() {
        let fs = MarkBaseFS::new("warren", "data/users/warren.sqlite");
        
        let result = {
            let conn = fs.sqlite.lock().unwrap();
            conn.query_row(
                "SELECT node_id, aliases_json FROM file_nodes 
                 WHERE node_type = 'file' 
                 AND aliases_json IS NOT NULL 
                 AND file_size < 1000 
                 LIMIT 1",
                [],
                |row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
            ).ok()
        };
        
        if let Some((node_id, aliases_json)) = result {
            let aliases: serde_json::Value = serde_json::from_str(&aliases_json).unwrap();
            let path = aliases["path"].as_str().unwrap_or_default();
            
            if !path.is_empty() && std::path::Path::new(path).exists() {
                let content = fs.read_file(&node_id);
                assert!(content.is_some());
                
                let data = content.unwrap();
                assert!(data.len() > 0);
                
                if let Ok(text) = String::from_utf8(data.clone()) {
                    println!("File content preview: {}", text.chars().take(100).collect::<String>());
                }
            }
        }
    }
    
    #[test]
    fn test_warren_statfs() {
        let conn = Connection::open("data/users/warren.sqlite").unwrap();
        
        let total_nodes: i64 = conn.query_row(
            "SELECT COUNT(*) FROM file_nodes",
            [],
            |row| row.get(0)
        ).unwrap();
        
        let total_size: i64 = conn.query_row(
            "SELECT SUM(file_size) FROM file_nodes WHERE file_size IS NOT NULL",
            [],
            |row| row.get(0)
        ).unwrap_or(0);
        
        println!("Total nodes: {}", total_nodes);
        println!("Total size: {} bytes ({:.2} GB)", 
            total_size, 
            total_size as f64 / 1_073_741_824.0
        );
        
        assert_eq!(total_nodes, 12659);
        assert!(total_size > 0);
    }
}