use std::path::PathBuf;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use anyhow::{Result, Error};

pub struct FuseOperations<'a> {
    fs: &'a MarkBaseFs,
}

struct QueryNodeResult {
    node_id: String,
    label: String,
    node_type: String,
    file_size: Option<i64>,
    parent_id: Option<String>,
    created_at: Option<i64>,
    updated_at: Option<i64>,
}

impl<'a> FuseOperations<'a> {
    pub fn new(fs: &'a MarkBaseFs) -> Self {
        FuseOperations { fs }
    }
    
    pub fn getattr(&self, ino: u64) -> Result<FileAttr> {
        let uuid = MarkBaseFs::ino_to_uuid(ino);
        
        let node = self.query_node(&uuid)?;
        
        let kind = match node.node_type.as_str() {
            "folder" => FileKind::Directory,
            "file" => FileKind::RegularFile,
            _ => FileKind::RegularFile,
        };
        
        let size = if kind == FileKind::RegularFile {
            node.file_size.unwrap_or(0) as u64
        } else {
            0
        };
        
        Ok(FileAttr {
            ino,
            size,
            mode: if kind == FileKind::Directory { 0o755 } else { 0o644 },
            nlink: if kind == FileKind::Directory { 2 } else { 1 },
            uid: 0,
            gid: 0,
            atime: node.updated_at.unwrap_or(0) as u64,
            mtime: node.updated_at.unwrap_or(0) as u64,
            ctime: node.created_at.unwrap_or(0) as u64,
            kind,
        })
    }
    
    pub fn readdir(&self, ino: u64) -> Result<Vec<(u64, String, FileKind)>> {
        let uuid = MarkBaseFs::ino_to_uuid(ino);
        
        let children = self.query_children(&uuid)?;
        
        let entries: Vec<(u64, String, FileKind)> = children
            .into_iter()
            .map(|node| {
                let child_ino = MarkBaseFs::uuid_to_ino(&node.node_id);
                let kind = match node.node_type.as_str() {
                    "folder" => FileKind::Directory,
                    "file" => FileKind::RegularFile,
                    _ => FileKind::RegularFile,
                };
                (child_ino, node.label, kind)
            })
            .collect();
        
        Ok(entries)
    }
    
    pub fn read(&self, ino: u64, offset: u64, size: u32) -> Result<Vec<u8>> {
        let uuid = MarkBaseFs::ino_to_uuid(ino);
        
        let path = self.get_file_path(&uuid)?;
        
        if !path.exists() {
            return Err(Error::msg("File not found"));
        }
        
        let mut file = File::open(&path)?;
        file.seek(SeekFrom::Start(offset))?;
        
        let mut buffer = vec![0u8; size as usize];
        let bytes_read = file.read(&mut buffer)?;
        buffer.truncate(bytes_read);
        
        Ok(buffer)
    }
    
    fn query_node(&self, uuid: &str) -> Result<QueryNodeResult> {
        use rusqlite::Connection;
        
        let db_path = self.fs.get_db_path();
        let conn = Connection::open(db_path)?;
        
        let node = conn.query_row(
            "SELECT node_id, label, node_type, file_size, parent_id, created_at, updated_at 
             FROM file_nodes 
             WHERE node_id = ?",
            [uuid],
            |row| {
                Ok(QueryNodeResult {
                    node_id: row.get::<_, String>(0)?,
                    label: row.get::<_, String>(1)?,
                    node_type: row.get::<_, String>(2)?,
                    file_size: row.get::<_, Option<i64>>(3)?,
                    parent_id: row.get::<_, Option<String>>(4)?,
                    created_at: row.get::<_, Option<i64>>(5)?,
                    updated_at: row.get::<_, Option<i64>>(6)?,
                })
            }
        )?;
        
        Ok(node)
    }
    
    fn query_children(&self, parent_uuid: &str) -> Result<Vec<QueryNodeResult>> {
        use rusqlite::Connection;
        
        let db_path = self.fs.get_db_path();
        let conn = Connection::open(db_path)?;
        
        let mut stmt = conn.prepare(
            "SELECT node_id, label, node_type, file_size, parent_id, created_at, updated_at 
             FROM file_nodes 
             WHERE parent_id = ? 
             ORDER BY sort_order, label"
        )?;
        
        let children = stmt.query_map([parent_uuid], |row| {
            Ok(QueryNodeResult {
                node_id: row.get::<_, String>(0)?,
                label: row.get::<_, String>(1)?,
                node_type: row.get::<_, String>(2)?,
                file_size: row.get::<_, Option<i64>>(3)?,
                parent_id: row.get::<_, Option<String>>(4)?,
                created_at: row.get::<_, Option<i64>>(5)?,
                updated_at: row.get::<_, Option<i64>>(6)?,
            })
        })?.collect::<Result<Vec<_>, _>>()?;
        
        Ok(children)
    }
    
    fn get_file_path(&self, uuid: &str) -> Result<PathBuf> {
        use rusqlite::Connection;
        
        let db_path = self.fs.get_db_path();
        let conn = Connection::open(db_path)?;
        
        let path_str = conn.query_row(
            "SELECT location FROM file_locations WHERE file_uuid = ?",
            [uuid],
            |row| row.get::<_, String>(0)
        )?;
        
        Ok(PathBuf::from(path_str))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::fuse::backend::BackendType;
    
    #[test]
    fn test_fuse_operations_creation() {
        let db_path = PathBuf::from("data/users/warren.sqlite");
        let fs = MarkBaseFs::new("warren".to_string(), db_path, BackendType::Fskit);
        let ops = FuseOperations::new(&fs);
        
        assert!(true);
    }
    
    #[test]
    fn test_uuid_roundtrip() {
        let uuid = "8b1ede3cd6970f02fa85b8e34b682caf";
        let ino = MarkBaseFs::uuid_to_ino(uuid);
        
        // Just verify the conversion produces a valid inode number
        assert!(ino > 0);
        
        // And that we can convert back
        let recovered = MarkBaseFs::ino_to_uuid(ino);
        assert!(!recovered.is_empty());
    }
}