#[cfg(test)]
mod comprehensive_tests {
    use filesystem_server::sandbox::Sandbox;
    use filesystem_server::tools::edit::{Edit, edit_file};
    use filesystem_server::tools::info::get_file_info;
    use filesystem_server::tools::read::{read_file, read_multiple_files};
    use filesystem_server::tools::search::{list_directory, search_files};
    use filesystem_server::tools::write::{create_directory, move_file, write_file};
    use std::os::unix::fs::PermissionsExt;
    use std::sync::Arc;
    use tempfile::TempDir;
    use tokio::fs as async_fs;

    async fn setup_sandbox(temp_dir: &TempDir) -> Arc<Sandbox> {
        let root = temp_dir.path().to_string_lossy().to_string();
        let sandbox = Sandbox::new(vec![root]).await.expect("sandbox init failed");
        Arc::new(sandbox)
    }

    // ==================== COMPREHENSIVE WORKFLOW TESTS ====================

    #[tokio::test]
    async fn test_complete_file_workflow() {
        let temp_dir = TempDir::new().unwrap();
        let sandbox = setup_sandbox(&temp_dir).await;
        // Use canonicalized path to handle macOS /var -> /private/var symlink
        let root = async_fs::canonicalize(temp_dir.path())
            .await
            .unwrap()
            .to_string_lossy()
            .to_string();

        // 1. Create directory
        let docs_dir = format!("{}/documents", root);
        create_directory(&sandbox, &docs_dir)
            .await
            .expect("create docs directory");

        // 2. Write file with initial content
        let file_path = format!("{}/README.md", docs_dir);
        write_file(
            &sandbox,
            &file_path,
            "# My Document\nVersion 1.0\n".to_string(),
        )
        .await
        .expect("write initial content");

        // 3. Read and verify initial content
        let initial_content = read_file(&sandbox, &file_path)
            .await
            .expect("read initial content");
        assert!(initial_content.contains("Version 1.0"));

        // 4. Edit the file
        let edits = vec![
            Edit {
                old: "Version 1.0".to_string(),
                new: "Version 2.0".to_string(),
            },
            Edit {
                old: "# My Document".to_string(),
                new: "# My Awesome Document".to_string(),
            },
        ];
        let edit_result = edit_file(&sandbox, &file_path, edits, false)
            .await
            .expect("edit file");
        assert!(edit_result.applied);

        // 5. Read and verify edited content
        let edited_content = read_file(&sandbox, &file_path)
            .await
            .expect("read edited content");
        assert!(edited_content.contains("Version 2.0"));
        assert!(edited_content.contains("# My Awesome Document"));

        // 6. Move file to new location
        let archived_dir = format!("{}/archived", root);
        create_directory(&sandbox, &archived_dir)
            .await
            .expect("create archived directory");

        let new_file_path = format!("{}/README.md", archived_dir);
        move_file(&sandbox, &file_path, &new_file_path)
            .await
            .expect("move file");

        // 7. Verify file was moved (old location should fail)
        let old_read = read_file(&sandbox, &file_path).await;
        assert!(old_read.is_err(), "File should not exist at old location");

        // 8. Verify file exists at new location with content preserved
        let moved_content = read_file(&sandbox, &new_file_path)
            .await
            .expect("read moved file");
        assert!(moved_content.contains("Version 2.0"));
        assert!(moved_content.contains("# My Awesome Document"));

        // 9. Get file info
        let metadata = get_file_info(&sandbox, &new_file_path)
            .await
            .expect("get file info");
        assert!(metadata.size > 0);
        assert!(!metadata.permissions.is_empty());

        // 10. List directory to verify structure
        let result = list_directory(&sandbox, &archived_dir)
            .await
            .expect("list archived directory");
        assert!(result.iter().any(|e| e.contains("README.md")));
    }

    #[tokio::test]
    async fn test_complete_permission_and_metadata_workflow() {
        let temp_dir = TempDir::new().unwrap();
        let sandbox = setup_sandbox(&temp_dir).await;
        // Use canonicalized path to handle macOS /var -> /private/var symlink
        let root = async_fs::canonicalize(temp_dir.path())
            .await
            .unwrap()
            .to_string_lossy()
            .to_string();

        // 1. Create directory and file
        let config_dir = format!("{}/config", root);
        create_directory(&sandbox, &config_dir)
            .await
            .expect("create config directory");

        let config_file = format!("{}/settings.json", config_dir);
        write_file(
            &sandbox,
            &config_file,
            r#"{"debug": true, "version": "1.0"}"#.to_string(),
        )
        .await
        .expect("write config file");

        // 2. Get initial metadata
        let initial = get_file_info(&sandbox, &config_file)
            .await
            .expect("get initial info");
        assert!(initial.size > 0);

        // 3. Edit file to change size
        let edits = vec![Edit {
            old: r#""debug": true"#.to_string(),
            new: r#""debug": false, "production": true"#.to_string(),
        }];
        edit_file(&sandbox, &config_file, edits, false)
            .await
            .expect("edit config");

        // 4. Get updated metadata
        let updated_info = get_file_info(&sandbox, &config_file)
            .await
            .expect("get updated info");
        assert!(
            updated_info.size > initial.size,
            "File should be larger after edit"
        );

        // 5. Set specific permissions and verify
        let file_path_pb = temp_dir.path().join("config/settings.json");
        let perms = std::fs::Permissions::from_mode(0o600);
        async_fs::set_permissions(&file_path_pb, perms)
            .await
            .expect("set permissions");

        let metadata = get_file_info(&sandbox, &config_file)
            .await
            .expect("get permissions info");
        assert_eq!(metadata.permissions, "600");

        // 6. Read final content and verify
        let final_content = read_file(&sandbox, &config_file)
            .await
            .expect("read final config");
        assert!(final_content.contains("production"));
        assert!(final_content.contains("false"));

        // 7. Move file and verify metadata preserved
        let backup_file = format!("{}/settings.json.backup", config_dir);
        move_file(&sandbox, &config_file, &backup_file)
            .await
            .expect("move to backup");

        let metadata = get_file_info(&sandbox, &backup_file)
            .await
            .expect("get backup info");
        assert_eq!(metadata.size, updated_info.size);
    }

    #[tokio::test]
    async fn test_complete_search_and_organize_workflow() {
        let temp_dir = TempDir::new().unwrap();
        let sandbox = setup_sandbox(&temp_dir).await;
        // Use canonicalized path to handle macOS /var -> /private/var symlink
        let root = async_fs::canonicalize(temp_dir.path())
            .await
            .unwrap()
            .to_string_lossy()
            .to_string();

        // 1. Create mixed directory structure
        let docs_dir = format!("{}/docs", root);
        let images_dir = format!("{}/images", root);
        let code_dir = format!("{}/code", root);

        create_directory(&sandbox, &docs_dir)
            .await
            .expect("create docs");
        create_directory(&sandbox, &images_dir)
            .await
            .expect("create images");
        create_directory(&sandbox, &code_dir)
            .await
            .expect("create code");

        // 2. Create various files
        write_file(
            &sandbox,
            &format!("{}/readme.md", docs_dir),
            "# Read me".to_string(),
        )
        .await
        .expect("write readme");
        write_file(
            &sandbox,
            &format!("{}/guide.md", docs_dir),
            "# Guide".to_string(),
        )
        .await
        .expect("write guide");
        write_file(
            &sandbox,
            &format!("{}/script.py", code_dir),
            "print('hello')".to_string(),
        )
        .await
        .expect("write python");
        write_file(
            &sandbox,
            &format!("{}/script.js", code_dir),
            "console.log('hello')".to_string(),
        )
        .await
        .expect("write js");
        write_file(
            &sandbox,
            &format!("{}/image.txt", images_dir),
            "fake image".to_string(),
        )
        .await
        .expect("write fake image");

        // 3. Search for Markdown files
        let result = search_files(&sandbox, &root, "*.md", vec![])
            .await
            .expect("search markdown");
        assert!(result.len() >= 2);
        assert!(result.iter().any(|f| f.ends_with("readme.md")));
        assert!(result.iter().any(|f| f.ends_with("guide.md")));

        // 4. Search excluding specific patterns
        let code_files = search_files(&sandbox, &code_dir, "*", vec!["*.txt".to_string()])
            .await
            .expect("search code files");
        assert!(code_files.len() >= 2);

        // 5. List each directory and verify content
        let docs = list_directory(&sandbox, &docs_dir)
            .await
            .expect("list docs");
        assert_eq!(docs.len(), 2);

        let code = list_directory(&sandbox, &code_dir)
            .await
            .expect("list code");
        assert_eq!(code.len(), 2);

        // 6. Edit a markdown file
        let readme_path = format!("{}/readme.md", docs_dir);
        let edits = vec![Edit {
            old: "# Read me".to_string(),
            new: "# Important Read Me\n\nPlease read this first!".to_string(),
        }];
        edit_file(&sandbox, &readme_path, edits, false)
            .await
            .expect("edit readme");

        let updated_readme = read_file(&sandbox, &readme_path)
            .await
            .expect("read updated readme");
        assert!(updated_readme.contains("Important"));

        // 7. Move markdown files to archive
        let archive_dir = format!("{}/archive", root);
        create_directory(&sandbox, &archive_dir)
            .await
            .expect("create archive");

        move_file(
            &sandbox,
            &readme_path,
            &format!("{}/readme.md", archive_dir),
        )
        .await
        .expect("move readme");
        move_file(
            &sandbox,
            &format!("{}/guide.md", docs_dir),
            &format!("{}/guide.md", archive_dir),
        )
        .await
        .expect("move guide");

        // 8. Verify final structure via search
        let remaining_md = search_files(&sandbox, &root, "*.md", vec![])
            .await
            .expect("search remaining markdown");
        assert!(remaining_md.iter().any(|f| f.contains("archive")));

        // 9. Get metadata on moved files
        let archived_readme = format!("{}/readme.md", archive_dir);
        let readme_info = get_file_info(&sandbox, &archived_readme)
            .await
            .expect("get archived readme info");
        assert!(readme_info.size > 20);

        // 10. Final verification - list archive directory
        let archive_entries = list_directory(&sandbox, &archive_dir)
            .await
            .expect("list archive");
        assert_eq!(archive_entries.len(), 2);
        assert!(archive_entries.iter().any(|e| e.contains("readme.md")));
        assert!(archive_entries.iter().any(|e| e.contains("guide.md")));
    }

    // ==================== SERVER TESTS ====================

    #[tokio::test]
    async fn test_server_with_multiple_sandbox_roots() {
        let temp_dir1 = TempDir::new().unwrap();
        let temp_dir2 = TempDir::new().unwrap();

        let root1 = temp_dir1.path().to_string_lossy().to_string();
        let root2 = temp_dir2.path().to_string_lossy().to_string();

        // 1. Create sandbox with multiple roots
        let roots = vec![root1.clone(), root2.clone()];
        let sandbox = Sandbox::new(roots)
            .await
            .expect("sandbox with multiple roots failed");

        // 2. Create and manage files in first root
        let proj1_dir = format!("{}/project1", root1);
        create_directory(&sandbox, &proj1_dir)
            .await
            .expect("create project1");

        let file1 = format!("{}/config.json", proj1_dir);
        write_file(&sandbox, &file1, r#"{"name": "Project 1"}"#.to_string())
            .await
            .expect("write project1 config");

        // 3. Create and manage files in second root
        let proj2_dir = format!("{}/project2", root2);
        create_directory(&sandbox, &proj2_dir)
            .await
            .expect("create project2");

        let file2 = format!("{}/config.json", proj2_dir);
        write_file(&sandbox, &file2, r#"{"name": "Project 2"}"#.to_string())
            .await
            .expect("write project2 config");

        // 4. Edit files in both roots
        let edits = vec![Edit {
            old: "Project 1".to_string(),
            new: "Project One".to_string(),
        }];
        edit_file(&sandbox, &file1, edits, false)
            .await
            .expect("edit project1");

        let edits2 = vec![Edit {
            old: "Project 2".to_string(),
            new: "Project Two".to_string(),
        }];
        edit_file(&sandbox, &file2, edits2, false)
            .await
            .expect("edit project2");

        // 5. Read and verify both files
        let content1 = read_file(&sandbox, &file1).await.expect("read project1");
        assert!(content1.contains("Project One"));

        let content2 = read_file(&sandbox, &file2).await.expect("read project2");
        assert!(content2.contains("Project Two"));

        // 5.5. Read multiple files at once
        let file_paths = vec![file1.clone(), file2.clone()];
        let multiple_contents = read_multiple_files(&sandbox, file_paths)
            .await
            .expect("read multiple files");
        assert_eq!(multiple_contents.len(), 2);
        assert!(multiple_contents[0].contains("Project One"));
        assert!(multiple_contents[1].contains("Project Two"));

        // 6. Move files
        let backup1 = format!("{}/backup.json", proj1_dir);
        move_file(&sandbox, &file1, &backup1)
            .await
            .expect("backup project1");

        let backup2 = format!("{}/backup.json", proj2_dir);
        move_file(&sandbox, &file2, &backup2)
            .await
            .expect("backup project2");

        // 7. Get metadata on backups
        let backup1_info = get_file_info(&sandbox, &backup1)
            .await
            .expect("get backup1 info");
        assert!(backup1_info.size > 0);

        let backup2_info = get_file_info(&sandbox, &backup2)
            .await
            .expect("get backup2 info");
        assert!(backup2_info.size > 0);

        // 8. List directories in both roots
        let result1 = list_directory(&sandbox, &root1).await.expect("list root1");
        assert!(result1.iter().any(|e| e.ends_with("/")));

        let result2 = list_directory(&sandbox, &root2).await.expect("list root2");
        assert!(result2.iter().any(|e| e.ends_with("/")));
    }

    #[tokio::test]
    async fn test_server_initialize_handler() {
        use filesystem_server::server::{AppContext, FilesystemServer};
        use rmcp::ServerHandler;

        let temp_dir = TempDir::new().unwrap();
        let root = temp_dir.path().to_string_lossy().to_string();

        // 1. Create sandbox and server
        let sandbox = Sandbox::new(vec![root]).await.expect("sandbox init failed");
        let ctx = Arc::new(AppContext {
            sandbox: Arc::new(sandbox),
        });

        let server = FilesystemServer::new(ctx);

        // 2. Test server initialization
        let info = server.get_info();
        assert_eq!(
            info.protocol_version.to_string(),
            "2025-06-18",
            "Protocol version should match expected"
        );
        assert_eq!(info.server_info.name, "rmcp");
        assert!(
            info.instructions.is_some(),
            "Server should have instructions"
        );

        // 3. Verify all operations are in instructions
        let instructions = info.instructions.unwrap();
        assert!(instructions.contains("list_directory"));
        assert!(instructions.contains("search_files"));
        assert!(instructions.contains("read_file"));
        assert!(instructions.contains("write_file"));
        assert!(instructions.contains("edit_file"));
        assert!(instructions.contains("create_directory"));
        assert!(instructions.contains("move_file"));
        assert!(instructions.contains("get_file_info"));
        assert!(instructions.contains("read_multiple_files"));
        assert!(instructions.contains("list_allowed_directories"));

        // 4. Verify capabilities
        assert!(
            info.capabilities.tools.is_some(),
            "Tools capability should be enabled"
        );
    }

    #[tokio::test]
    async fn test_filesystem_server_initialization() {
        use filesystem_server::server::{AppContext, FilesystemServer};

        let temp_dir = TempDir::new().unwrap();
        let root = temp_dir.path().to_string_lossy().to_string();

        // Create sandbox and server
        let sandbox = Sandbox::new(vec![root.clone()])
            .await
            .expect("sandbox init failed");
        let ctx = Arc::new(AppContext {
            sandbox: Arc::new(sandbox),
        });

        let _server = FilesystemServer::new(ctx.clone());

        // Verify server was created successfully
        assert!(!root.is_empty());

        // Create a test file through the server's sandbox
        let file_path = temp_dir.path().join("server_test.txt");
        write_file(
            &ctx.sandbox,
            file_path.to_str().unwrap(),
            "Server test content".to_string(),
        )
        .await
        .expect("write file through server");

        // Verify file exists and can be read
        let content = read_file(&ctx.sandbox, file_path.to_str().unwrap())
            .await
            .expect("read file through server");
        assert_eq!(content, "Server test content");
    }

    #[tokio::test]
    async fn test_filesystem_server_router() {
        use filesystem_server::build_router;

        let temp_dir = TempDir::new().unwrap();
        let root = temp_dir.path().to_string_lossy().to_string();

        // Build router with sandbox roots
        let _router = build_router(vec![root.clone()])
            .await
            .expect("router build failed");

        // Verify router was created
        // The router should be a valid Axum router
        assert!(!root.is_empty());
    }

    // ==================== CLI ARGUMENTS TEST ====================

    #[test]
    fn test_cli_args_parsing() {
        use clap::Parser;

        // Mock the CLI args structure from main.rs
        #[derive(Parser, Debug)]
        struct Args {
            #[arg(long)]
            roots: Vec<String>,
        }

        // Test with single root
        let args = Args::parse_from(["program", "--roots", "/tmp/root1"]);
        assert_eq!(args.roots.len(), 1);
        assert_eq!(args.roots[0], "/tmp/root1");

        // Test with multiple roots
        let args = Args::parse_from(["program", "--roots", "/tmp/root1", "--roots", "/tmp/root2"]);
        assert_eq!(args.roots.len(), 2);
        assert_eq!(args.roots[0], "/tmp/root1");
        assert_eq!(args.roots[1], "/tmp/root2");

        // Test with no roots
        let args = Args::parse_from(["program"]);
        assert_eq!(args.roots.len(), 0);
    }

    #[tokio::test]
    async fn test_cli_args_sandbox_creation() {
        let temp_dir1 = TempDir::new().unwrap();
        let temp_dir2 = TempDir::new().unwrap();

        let root1 = temp_dir1.path().to_string_lossy().to_string();
        let root2 = temp_dir2.path().to_string_lossy().to_string();

        // Simulate CLI args with multiple roots
        let roots = vec![root1.clone(), root2.clone()];

        // Create sandbox with multiple roots
        let sandbox = Sandbox::new(roots)
            .await
            .expect("sandbox with multiple roots failed");

        // Write file in first root
        let file1 = temp_dir1.path().join("file1.txt");
        write_file(&sandbox, file1.to_str().unwrap(), "From root1".to_string())
            .await
            .expect("write to root1");

        // Write file in second root
        let file2 = temp_dir2.path().join("file2.txt");
        write_file(&sandbox, file2.to_str().unwrap(), "From root2".to_string())
            .await
            .expect("write to root2");

        // Verify both files exist and are accessible
        let content1 = read_file(&sandbox, file1.to_str().unwrap())
            .await
            .expect("read from root1");
        assert_eq!(content1, "From root1");

        let content2 = read_file(&sandbox, file2.to_str().unwrap())
            .await
            .expect("read from root2");
        assert_eq!(content2, "From root2");

        // Verify listing works on both roots
        let result = list_directory(&sandbox, root1.as_str())
            .await
            .expect("list root1");
        assert!(result.iter().any(|e| e.contains("file1")));

        let result2 = list_directory(&sandbox, root2.as_str())
            .await
            .expect("list root2");
        assert!(result2.iter().any(|e| e.contains("file2")));
    }
}
