import "reflect-metadata";
import { 
  MetadataRegistry, 
  SchemaBuilder 
} from "../../core";
import { Neo4jAdapter } from "../../adapters/neo4j";
import { User } from "../../examples/blog/User";
import { Post } from "../../examples/blog/Post";
import { Tag } from "../../examples/blog/Tag";
import { ComplexUser } from "../fixtures/ComplexUser";

/**
 * Neo4j Adapter Bulletproof Tests
 * These tests shoot AK-47s at the adapter to ensure it's bulletproof
 */
describe("Neo4jAdapter - Bulletproof Tests", () => {
  let registry: MetadataRegistry;
  let builder: SchemaBuilder;
  let adapter: Neo4jAdapter;
  let mockDriver: any;
  let mockSession: any;
  let mockTransaction: any;
  let mockResult: any;
  
  beforeEach(() => {
    registry = new MetadataRegistry();
    builder = new SchemaBuilder(registry);
    builder.registerEntities([User, Post, Tag, ComplexUser]);
    
    // Debug: Check if ComplexUser was registered
    const entityMetadata = registry.getEntityMetadata(ComplexUser);
    if (!entityMetadata) {
      console.log("WARNING: ComplexUser not registered in metadata registry");
    }
    
    // Create mock result
    mockResult = {
      records: [],
      summary: {
        counters: {
          updates: jest.fn().mockReturnValue({})
        },
        resultAvailableAfter: 0,
        resultConsumedAfter: 0,
        query: {
          text: "",
          parameters: {}
        }
      }
    };
    
    // Create mock transaction
    mockTransaction = {
      run: jest.fn().mockResolvedValue(mockResult),
      commit: jest.fn().mockResolvedValue(undefined),
      rollback: jest.fn().mockResolvedValue(undefined)
    };
    
    // Create mock session
    mockSession = {
      run: jest.fn().mockResolvedValue(mockResult),
      close: jest.fn().mockResolvedValue(undefined),
      beginTransaction: jest.fn().mockReturnValue(mockTransaction)
    };
    
    // Create mock driver
    mockDriver = {
      session: jest.fn().mockReturnValue(mockSession),
      verifyConnectivity: jest.fn().mockResolvedValue(undefined),
      close: jest.fn().mockResolvedValue(undefined)
    };
    
    adapter = new Neo4jAdapter(registry, "bolt://localhost:7687");
    
    // Mock the private driver and neo4j properties
    (adapter as any).driver = mockDriver;
    (adapter as any).initialized = true;
    (adapter as any).neo4j = {
      driver: jest.fn().mockReturnValue(mockDriver),
      session: { READ: 'READ', WRITE: 'WRITE' },
      auth: { basic: jest.fn().mockReturnValue({ username: 'neo4j', password: 'password' }) },
      isNode: jest.fn().mockReturnValue(false),
      isRelationship: jest.fn().mockReturnValue(false),
      isPath: jest.fn().mockReturnValue(false),
      isDate: jest.fn().mockReturnValue(false),
      isDateTime: jest.fn().mockReturnValue(false),
      isTime: jest.fn().mockReturnValue(false),
      isLocalTime: jest.fn().mockReturnValue(false),
      isLocalDateTime: jest.fn().mockReturnValue(false),
      isDuration: jest.fn().mockReturnValue(false)
    };
  });
  
  afterEach(() => {
    jest.clearAllMocks();
  });

  // ==============================================
  // PHASE 1: FOUNDATION HARDENING - AK-47 ROUND 1
  // ==============================================
  
  describe("Phase 1: Foundation Hardening", () => {
    
    describe("Connection Failure Scenarios", () => {
      
      test("should handle invalid connection string gracefully", async () => {
        const invalidAdapter = new Neo4jAdapter(registry, "invalid://connection");
        
        // Mock the initialization to fail
        (invalidAdapter as any).initialize = jest.fn().mockRejectedValue(new Error("invalid connection"));
        
        // Force initialization to trigger connection
        await expect(invalidAdapter.query(User, { id: "test" })).rejects.toThrow("invalid connection");
      });
      
      test("should handle connection timeout", async () => {
        mockDriver.verifyConnectivity.mockRejectedValueOnce(new Error("connection timeout"));
        (adapter as any).initialized = false;
        
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow("connection timeout");
      });
      
      test("should handle authentication failure", async () => {
        mockDriver.verifyConnectivity.mockRejectedValueOnce(new Error("authentication failed"));
        (adapter as any).initialized = false;
        
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow("authentication failed");
      });
      
      test("should handle Neo4j service unavailable", async () => {
        mockDriver.verifyConnectivity.mockRejectedValueOnce(new Error("Neo4j service unavailable"));
        (adapter as any).initialized = false;
        
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow("Neo4j service unavailable");
      });
      
      test("should handle connection loss during operation", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("connection lost"));
        
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow("connection lost");
        
        // Verify session was closed despite error
        expect(mockSession.close).toHaveBeenCalled();
      });
      
      test("should handle null/undefined driver", async () => {
        (adapter as any).driver = null;
        (adapter as any).initialized = true;
        
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow("Driver not initialized");
      });
      
      test("should handle bolt protocol version mismatch", async () => {
        mockDriver.verifyConnectivity.mockRejectedValueOnce(new Error("protocol version not supported"));
        (adapter as any).initialized = false;
        
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow("protocol version not supported");
      });
      
    });
    
    describe("Cypher Injection Protection", () => {
      
      test("should handle malicious Cypher in criteria values", async () => {
        const maliciousCriteria = {
          id: "'; MATCH (n) DETACH DELETE n; //"
        };
        
        await adapter.query(User, maliciousCriteria);
        
        // Verify parameterized query was used
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$id"),
          expect.objectContaining({ id: "'; MATCH (n) DETACH DELETE n; //" })
        );
      });
      
      test("should handle Cypher injection in multiple criteria", async () => {
        const maliciousCriteria = {
          id: "1'; MATCH (n) DETACH DELETE n; //",
          email: "test@example.com'; CREATE (evil:Virus); //"
        };
        
        await adapter.query(User, maliciousCriteria);
        
        // Verify both values were parameterized
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$id"),
          expect.objectContaining({
            id: "1'; MATCH (n) DETACH DELETE n; //",
            email: "test@example.com'; CREATE (evil:Virus); //"
          })
        );
      });
      
      test("should handle Cypher injection in native query parameters", async () => {
        const maliciousParams = { id: "'; MATCH (n) DETACH DELETE n; //" };
        
        await adapter.runNativeQuery("MATCH (n:User) WHERE n.id = $id RETURN n", maliciousParams);
        
        // Verify parameters were passed through safely
        expect(mockSession.run).toHaveBeenCalledWith(
          "MATCH (n:User) WHERE n.id = $id RETURN n",
          maliciousParams
        );
      });
      
      test("should handle null/undefined criteria safely", async () => {
        await adapter.query(User, { id: null });
        await adapter.query(User, { id: undefined });
        
        // Should not throw and should handle null/undefined values
        expect(mockSession.run).toHaveBeenCalledTimes(2);
      });
      
      test("should handle complex object criteria", async () => {
        const complexCriteria = {
          metadata: { key: "value'; MATCH (n) DETACH DELETE n; //" },
          nested: {
            deep: "'; CREATE (evil:Virus); //"
          }
        };
        
        await adapter.query(User, complexCriteria);
        
        // Should handle complex objects without injection
        expect(mockSession.run).toHaveBeenCalled();
      });
      
      test("should handle APOC injection attempts", async () => {
        const apocCriteria = {
          id: "'; CALL apoc.periodic.iterate('MATCH (n) RETURN n', 'DETACH DELETE n', {}); //"
        };
        
        await adapter.query(User, apocCriteria);
        
        // Should parameterize dangerous APOC calls
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$id"),
          expect.objectContaining({ id: "'; CALL apoc.periodic.iterate('MATCH (n) RETURN n', 'DETACH DELETE n', {}); //" })
        );
      });
      
    });
    
    describe("Entity Validation Edge Cases", () => {
      
      test("should handle circular reference in entities", async () => {
        const user1 = new ComplexUser();
        const user2 = new ComplexUser();
        
        user1.id = "user1";
        user1.name = "User 1";
        user1.email = "user1@example.com";
        user1.status = "active";
        user1.managers = [user2];
        
        user2.id = "user2";
        user2.name = "User 2";
        user2.email = "user2@example.com";
        user2.status = "active";
        user2.managers = [user1]; // Circular reference
        
        // Should not cause infinite loop
        await expect(adapter.save(user1)).resolves.not.toThrow();
      });
      
      test("should handle deeply nested relationship validation", async () => {
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        const post = new Post();
        post.id = "post1";
        post.title = "Test Post";
        post.content = "Content";
        post.author = user;
        
        const tag = new Tag();
        tag.id = "tag1";
        tag.name = "Test Tag";
        tag.posts = [post];
        
        post.tags = [tag];
        user.posts = [post];
        
        // Should handle complex nested relationships
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
      test("should handle entity with missing required properties", async () => {
        const invalidUser = new User();
        invalidUser.id = "test";
        // Missing required name and email
        
        await expect(adapter.save(invalidUser)).rejects.toThrow(/Invalid entity/);
      });
      
      test("should handle entity with invalid property types", async () => {
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        // Invalid type assignment
        (user as any).createdAt = "invalid-date";
        
        // Should not throw during save (type coercion handled by Neo4j)
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
      test("should handle entity with undefined relationships", async () => {
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        user.posts = undefined as any;
        
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
      test("should handle entity with null ID during save", async () => {
        const user = new User();
        user.id = null as any;
        user.name = "Test User";
        user.email = "test@example.com";
        
        // Should handle null ID (should fail for Neo4j)
        await expect(adapter.save(user)).rejects.toThrow();
      });
      
      test("should handle entity with duplicate unique properties", async () => {
        mockTransaction.run.mockRejectedValueOnce(new Error("Node already exists with label"));
        
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "existing@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("Node already exists with label");
      });
      
      test("should handle Neo4j integer overflow", async () => {
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        (user as any).bigNumber = Number.MAX_SAFE_INTEGER + 1;
        
        // Should handle large numbers
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
    });
    
    describe("Query Parameter Edge Cases", () => {
      
      test("should handle empty criteria object", async () => {
        await adapter.query(User, {});
        
        // Should generate query without WHERE clause
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringMatching(/MATCH \(n:User\)\s*RETURN n LIMIT 1/),
          {}
        );
      });
      
      test("should handle criteria with special characters", async () => {
        const criteria = {
          name: "Test User @#$%^&*()_+-=[]{}|;':,./<>?"
        };
        
        await adapter.query(User, criteria);
        
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$name"),
          expect.objectContaining({ name: "Test User @#$%^&*()_+-=[]{}|;':,./<>?" })
        );
      });
      
      test("should handle criteria with unicode characters", async () => {
        const criteria = {
          name: "用户测试 🚀 émojis"
        };
        
        await adapter.query(User, criteria);
        
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$name"),
          expect.objectContaining({ name: "用户测试 🚀 émojis" })
        );
      });
      
      test("should handle very long string criteria", async () => {
        const longString = "a".repeat(10000);
        const criteria = {
          name: longString
        };
        
        await adapter.query(User, criteria);
        
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$name"),
          expect.objectContaining({ name: longString })
        );
      });
      
      test("should handle array values in criteria", async () => {
        const criteria = {
          id: ["1", "2", "3"]
        };
        
        await adapter.query(User, criteria);
        
        // Should handle array values appropriately
        expect(mockSession.run).toHaveBeenCalled();
      });
      
      test("should handle boolean values in criteria", async () => {
        const criteria = {
          active: true
        };
        
        await adapter.query(User, criteria);
        
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$active"),
          expect.objectContaining({ active: true })
        );
      });
      
      test("should handle numeric values in criteria", async () => {
        const criteria = {
          age: 25,
          score: 99.5,
          bigNumber: 9007199254740991
        };
        
        await adapter.query(User, criteria);
        
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$bigNumber"),
          expect.objectContaining({ age: 25, score: 99.5, bigNumber: 9007199254740991 })
        );
      });
      
      test("should handle Neo4j temporal types in criteria", async () => {
        const criteria = {
          createdAt: new Date("2023-01-01T00:00:00Z")
        };
        
        await adapter.query(User, criteria);
        
        expect(mockSession.run).toHaveBeenCalledWith(
          expect.stringContaining("$createdAt"),
          expect.objectContaining({ createdAt: new Date("2023-01-01T00:00:00Z") })
        );
      });
      
    });
    
    describe("Database Operation Edge Cases", () => {
      
      test("should handle query with no results", async () => {
        mockResult.records = [];
        
        const result = await adapter.query(User, { id: "nonexistent" });
        
        expect(result).toBeNull();
      });
      
      test("should handle queryMany with no results", async () => {
        mockResult.records = [];
        
        const results = await adapter.queryMany(User, { status: "active" });
        
        expect(results).toEqual([]);
      });
      
      test("should handle delete with no matching records", async () => {
        mockResult.records = [];
        
        await expect(adapter.delete(User, "nonexistent")).resolves.not.toThrow();
      });
      
      test("should handle runNativeQuery with syntax error", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Invalid syntax"));
        
        await expect(adapter.runNativeQuery("MTCH (n) RETURN n")).rejects.toThrow("Invalid syntax");
      });
      
      test("should handle runNativeQuery with permission error", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Permission denied"));
        
        await expect(adapter.runNativeQuery("CALL dbms.security.createUser('hacker', 'password')")).rejects.toThrow("Permission denied");
      });
      
      test("should handle session close failure", async () => {
        mockSession.close.mockImplementation(() => {
          throw new Error("close failed");
        });
        
        // Should throw because close failure bubbles up
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow("close failed");
      });
      
      test("should handle adapter close with no driver", async () => {
        (adapter as any).driver = null;
        
        await expect(adapter.close()).resolves.not.toThrow();
      });
      
      test("should handle adapter close with driver close failure", async () => {
        mockDriver.close.mockRejectedValueOnce(new Error("driver close failed"));
        
        await expect(adapter.close()).rejects.toThrow("driver close failed");
      });
      
      test("should handle Neo4j constraint violations", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Node already exists with label"));
        
        await expect(adapter.query(User, { id: "duplicate" })).rejects.toThrow("Node already exists with label");
      });
      
    });
    
  });

  // ==============================================
  // PHASE 2: TRANSACTION WARFARE - AK-47 ROUND 2
  // ==============================================
  
  describe("Phase 2: Transaction Warfare", () => {
    
    describe("Transaction Rollback Scenarios", () => {
      
      test("should handle transaction rollback on save failure", async () => {
        // Mock successful transaction start, then failure, then successful rollback
        mockTransaction.run
          .mockResolvedValueOnce({ records: [], summary: { counters: { updates: () => ({}) } } }) // Initial node creation
          .mockRejectedValueOnce(new Error("constraint violation")); // Relationship creation fails
        
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("constraint violation");
        
        // Verify transaction was rolled back
        expect(mockTransaction.rollback).toHaveBeenCalled();
      });
      
      test("should handle rollback failure after save failure", async () => {
        // Mock transaction failure followed by rollback failure
        mockTransaction.run.mockRejectedValueOnce(new Error("constraint violation"));
        mockTransaction.rollback.mockRejectedValueOnce(new Error("rollback failed"));
        
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        // Should throw the rollback error, not the original error
        await expect(adapter.save(user)).rejects.toThrow("rollback failed");
      });
      
      test("should handle nested transaction failures", async () => {
        // Mock a scenario where relationship saves trigger nested operations
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        const post = new Post();
        post.id = "post1";
        post.title = "Test Post";
        post.content = "Content";
        post.author = user;
        
        user.posts = [post];
        
        // Mock the main transaction succeeding but relationship transaction failing
        mockTransaction.run
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "test" } }) }] }) // User creation
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "post1" } }) }] }) // Post creation
          .mockRejectedValueOnce(new Error("relationship constraint violation")); // Relationship creation fails
        
        await expect(adapter.save(user)).rejects.toThrow("relationship constraint violation");
      });
      
      test("should handle connection loss during transaction", async () => {
        mockTransaction.run.mockRejectedValueOnce(new Error("connection lost"));
        
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("connection lost");
      });
      
      test("should handle deadlock detection and retry", async () => {
        mockTransaction.run.mockRejectedValueOnce(new Error("DeadlockDetectedException"));
        
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("DeadlockDetectedException");
      });
      
      test("should handle transaction timeout", async () => {
        mockTransaction.run.mockRejectedValueOnce(new Error("Transaction timeout"));
        
        const user = new User();
        user.id = "test";
        user.name = "Test User";
        user.email = "test@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("Transaction timeout");
      });
      
    });
    
    describe("Concurrent Operation Testing", () => {
      
      test("should handle multiple saves of same entity", async () => {
        const user = new User();
        user.id = "concurrent-test";
        user.name = "Concurrent User";
        user.email = "concurrent@example.com";
        
        // Mock different responses for each concurrent save
        let callCount = 0;
        mockTransaction.run.mockImplementation(() => {
          callCount++;
          if (callCount <= 2) {
            return Promise.resolve({ records: [], summary: { counters: { updates: () => ({}) } } });
          } else {
            return Promise.reject(new Error("concurrent modification"));
          }
        });
        
        // Simulate concurrent saves
        const savePromises = [
          adapter.save(user),
          adapter.save(user),
          adapter.save(user)
        ];
        
        // At least one should fail due to concurrent modification
        const results = await Promise.allSettled(savePromises);
        const hasFailure = results.some(result => result.status === "rejected");
        
        expect(hasFailure).toBe(true);
      });
      
      test("should handle race conditions in relationships", async () => {
        const user = new User();
        user.id = "race-test";
        user.name = "Race User";
        user.email = "race@example.com";
        
        const post1 = new Post();
        post1.id = "post1";
        post1.title = "Post 1";
        post1.content = "Content 1";
        post1.author = user;
        
        const post2 = new Post();
        post2.id = "post2";
        post2.title = "Post 2";
        post2.content = "Content 2";
        post2.author = user;
        
        user.posts = [post1, post2];
        
        // Mock race condition in relationship handling
        mockTransaction.run
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "race-test" } }) }] }) // User creation
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "post1" } }) }] }) // Post1 creation
          .mockRejectedValueOnce(new Error("relationship already exists")); // Race in relationship creation
        
        await expect(adapter.save(user)).rejects.toThrow("relationship already exists");
      });
      
      test("should handle session pool contention", async () => {
        // Simulate session exhaustion
        mockDriver.session
          .mockImplementationOnce(() => { throw new Error("session pool exhausted"); })
          .mockImplementationOnce(() => { throw new Error("session pool exhausted"); })
          .mockImplementationOnce(() => mockSession); // Finally succeeds
        
        const user = new User();
        user.id = "pool-test";
        user.name = "Pool User";
        user.email = "pool@example.com";
        
        // First two attempts should fail
        await expect(adapter.query(User, { id: "test1" })).rejects.toThrow("session pool exhausted");
        await expect(adapter.query(User, { id: "test2" })).rejects.toThrow("session pool exhausted");
        
        // Third should succeed
        await expect(adapter.query(User, { id: "test3" })).resolves.toBeNull();
      });
      
      test("should handle atomic operation failures", async () => {
        // Test atomic operations that must either all succeed or all fail
        const user = new User();
        user.id = "atomic-test";
        user.name = "Atomic User";
        user.email = "atomic@example.com";
        
        // Mock partial success followed by failure
        mockTransaction.run
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "atomic-test" } }) }] }) // User creation succeeds
          .mockRejectedValueOnce(new Error("index violation")); // Related operation fails
        
        await expect(adapter.save(user)).rejects.toThrow("index violation");
        
        // Verify rollback was called
        expect(mockTransaction.rollback).toHaveBeenCalled();
      });
      
      test("should handle Neo4j cluster failover", async () => {
        mockDriver.session
          .mockImplementationOnce(() => { throw new Error("cluster member unavailable"); })
          .mockImplementationOnce(() => mockSession); // Failover succeeds
        
        await expect(adapter.query(User, { id: "test1" })).rejects.toThrow("cluster member unavailable");
        await expect(adapter.query(User, { id: "test2" })).resolves.toBeNull();
      });
      
    });
    
  });

  // ==============================================
  // PHASE 3: RELATIONSHIP COMPLEXITY - AK-47 ROUND 3
  // ==============================================
  
  describe("Phase 3: Relationship Complexity", () => {
    
    describe("Complex Relationship Scenarios", () => {
      
      test("should handle self-referencing entity relationships", async () => {
        const manager = new ComplexUser();
        manager.id = "manager1";
        manager.name = "Manager";
        manager.email = "manager@example.com";
        manager.status = "active";
        
        const employee = new ComplexUser();
        employee.id = "employee1";
        employee.name = "Employee";
        employee.email = "employee@example.com";
        employee.status = "active";
        employee.managers = [manager];
        
        manager.managedUsers = [employee];
        
        // Should handle self-referencing relationships
        await expect(adapter.save(manager)).resolves.not.toThrow();
      });
      
      test("should handle orphaned relationship cleanup", async () => {
        const user = new User();
        user.id = "orphan-test";
        user.name = "Orphan User";
        user.email = "orphan@example.com";
        
        // Mock scenario where related entities become orphaned
        mockTransaction.run
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "orphan-test" } }) }] }) // User creation
          .mockRejectedValueOnce(new Error("orphaned relationship")); // Orphan cleanup fails
        
        await expect(adapter.save(user)).rejects.toThrow("orphaned relationship");
      });
      
      test("should handle deeply nested relationship saves", async () => {
        const user = new User();
        user.id = "deep-test";
        user.name = "Deep User";
        user.email = "deep@example.com";
        
        const post = new Post();
        post.id = "deep-post";
        post.title = "Deep Post";
        post.content = "Content";
        post.author = user;
        
        const tag1 = new Tag();
        tag1.id = "tag1";
        tag1.name = "Tag 1";
        tag1.posts = [post];
        
        const tag2 = new Tag();
        tag2.id = "tag2";
        tag2.name = "Tag 2";
        tag2.posts = [post];
        
        post.tags = [tag1, tag2];
        user.posts = [post];
        
        // Mock successful deep save
        mockTransaction.run.mockResolvedValue({ records: [{ get: () => ({ properties: { id: "test" } }) }] });
        
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
      test("should handle relationship direction validation", async () => {
        const user = new User();
        user.id = "direction-test";
        user.name = "Direction User";
        user.email = "direction@example.com";
        
        const post = new Post();
        post.id = "direction-post";
        post.title = "Direction Post";
        post.content = "Content";
        post.author = user;
        
        // Mock with proper relationship direction
        mockTransaction.run.mockResolvedValue({ records: [{ get: () => ({ properties: { id: "test" } }) }] });
        
        await expect(adapter.save(user)).resolves.not.toThrow();
        
        // Verify relationship direction in Cypher query
        expect(mockTransaction.run).toHaveBeenCalledWith(
          expect.stringContaining("MERGE (n)-[r:"),
          expect.any(Object)
        );
      });
      
    });
    
    describe("Relationship Type Operations", () => {
      
      test("should handle custom relationship types", async () => {
        const user = new User();
        user.id = "custom-rel-test";
        user.name = "Custom Rel User";
        user.email = "custom@example.com";
        
        // Add custom relationship metadata
        Reflect.defineMetadata("neo4j:relationship", { type: "CUSTOM_AUTHORED", direction: "OUT" }, User.prototype, "posts");
        
        const post = new Post();
        post.id = "custom-post";
        post.title = "Custom Post";
        post.content = "Content";
        post.author = user;
        
        user.posts = [post];
        
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
      test("should handle relationship property updates", async () => {
        mockTransaction.run
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "test" } }) }] }) // Node creation
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "related" } }) }] }) // Related node
          .mockResolvedValueOnce({ records: [] }); // Relationship deletion
        
        const user = new User();
        user.id = "rel-prop-test";
        user.name = "Rel Prop User";
        user.email = "relprop@example.com";
        
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
      test("should handle bidirectional relationships", async () => {
        const user1 = new User();
        user1.id = "user1";
        user1.name = "User 1";
        user1.email = "user1@example.com";
        
        const user2 = new User();
        user2.id = "user2";
        user2.name = "User 2";
        user2.email = "user2@example.com";
        
        // Create bidirectional relationship
        user1.following = [user2];
        user2.followers = [user1];
        
        await expect(adapter.save(user1)).resolves.not.toThrow();
      });
      
      test("should handle relationship constraint violations", async () => {
        mockTransaction.run
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "test" } }) }] }) // Node creation
          .mockRejectedValueOnce(new Error("relationship constraint violation")); // Relationship fails
        
        const user = new User();
        user.id = "constraint-test";
        user.name = "Constraint User";
        user.email = "constraint@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("relationship constraint violation");
      });
      
    });
    
  });

  // ==============================================
  // PHASE 4: DATA INTEGRITY ARTILLERY - AK-47 ROUND 4
  // ==============================================
  
  describe("Phase 4: Data Integrity Artillery", () => {
    
    describe("Schema Evolution Scenarios", () => {
      
      test("should handle missing label gracefully", async () => {
        mockSession.run.mockRejectedValueOnce(new Error('Label `MissingLabel` not found'));
        
        await expect(adapter.query(User, { id: "test" })).rejects.toThrow('Label `MissingLabel` not found');
      });
      
      test("should handle missing property gracefully", async () => {
        mockSession.run.mockRejectedValueOnce(new Error('Property `missing_property` does not exist'));
        
        await expect(adapter.query(User, { missingProperty: "value" })).rejects.toThrow('Property `missing_property` does not exist');
      });
      
      test("should handle property type mismatch", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Type mismatch: expected Number but was String"));
        
        const user = new User();
        user.id = "type-test";
        user.name = "Type User";
        user.email = "type@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("Type mismatch: expected Number but was String");
      });
      
      test("should handle constraint creation failures", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Constraint creation failed"));
        
        await expect(adapter.runNativeQuery("CREATE CONSTRAINT ON (n:User) ASSERT n.email IS UNIQUE")).rejects.toThrow("Constraint creation failed");
      });
      
      test("should handle index creation failures", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Index creation failed"));
        
        await expect(adapter.runNativeQuery("CREATE INDEX ON :User(name)")).rejects.toThrow("Index creation failed");
      });
      
    });
    
    describe("Data Corruption Scenarios", () => {
      
      test("should handle partial write failures", async () => {
        // Mock scenario where some data is written but transaction fails
        mockTransaction.run
          .mockResolvedValueOnce({ records: [{ get: () => ({ properties: { id: "partial" } }) }] }) // Partial write succeeds
          .mockRejectedValueOnce(new Error("disk full")); // Next operation fails
        
        const user = new User();
        user.id = "partial-test";
        user.name = "Partial User";
        user.email = "partial@example.com";
        
        await expect(adapter.save(user)).rejects.toThrow("disk full");
        expect(mockTransaction.rollback).toHaveBeenCalled();
      });
      
      test("should handle encoding issues", async () => {
        const user = new User();
        user.id = "encoding-test";
        user.name = "Encoding \x00\x01\x02 User"; // Binary data
        user.email = "encoding@example.com";
        
        mockTransaction.run.mockRejectedValueOnce(new Error("invalid byte sequence"));
        
        await expect(adapter.save(user)).rejects.toThrow("invalid byte sequence");
      });
      
      test("should handle very large data", async () => {
        const largeContent = "x".repeat(1000000); // 1MB string
        
        const user = new User();
        user.id = "large-test";
        user.name = largeContent;
        user.email = "large@example.com";
        
        mockTransaction.run.mockRejectedValueOnce(new Error("value too long"));
        
        await expect(adapter.save(user)).rejects.toThrow("value too long");
      });
      
      test("should handle Neo4j temporal data edge cases", async () => {
        const user = new User();
        user.id = "temporal-test";
        user.name = "Temporal User";
        user.email = "temporal@example.com";
        (user as any).createdAt = new Date("invalid-date");
        
        // Should handle invalid dates gracefully
        await expect(adapter.save(user)).resolves.not.toThrow();
      });
      
      test("should handle Neo4j spatial data corruption", async () => {
        const user = new User();
        user.id = "spatial-test";
        user.name = "Spatial User";
        user.email = "spatial@example.com";
        (user as any).location = { type: "Point", coordinates: [NaN, NaN] };
        
        mockTransaction.run.mockRejectedValueOnce(new Error("Invalid coordinate"));
        
        await expect(adapter.save(user)).rejects.toThrow("Invalid coordinate");
      });
      
    });
    
  });

  // ==============================================
  // PHASE 5: PERFORMANCE UNDER FIRE - AK-47 ROUND 5
  // ==============================================
  
  describe("Phase 5: Performance Under Fire", () => {
    
    describe("Resource Exhaustion Testing", () => {
      
      test("should handle memory leaks in session pool", async () => {
        // Simulate memory pressure
        const originalMemoryUsage = process.memoryUsage();
        
        // Create many sessions without proper cleanup
        for (let i = 0; i < 100; i++) {
          mockDriver.session.mockReturnValueOnce({
            run: jest.fn().mockResolvedValue({ records: [] }),
            close: jest.fn() // Don't actually cleanup
          });
          
          await adapter.query(User, { id: `test${i}` });
        }
        
        const currentMemoryUsage = process.memoryUsage();
        
        // Memory usage should not grow significantly
        const memoryGrowth = currentMemoryUsage.heapUsed - originalMemoryUsage.heapUsed;
        expect(memoryGrowth).toBeLessThan(50 * 1024 * 1024); // Less than 50MB growth
      });
      
      test("should handle large result set processing", async () => {
        // Mock a very large result set
        const largeResultSet = Array.from({ length: 10000 }, (_, i) => ({
          get: (key: string) => ({
            properties: {
              id: `user${i}`,
              name: `User ${i}`,
              email: `user${i}@example.com`
            }
          })
        }));
        
        mockResult.records = largeResultSet;
        
        const results = await adapter.queryMany(User, { active: true });
        
        expect(results).toHaveLength(10000);
        expect(results[0]).toBeInstanceOf(User);
      });
      
      test("should handle query timeout scenarios", async () => {
        mockSession.run.mockImplementation(() => {
          return new Promise((_, reject) => {
            setTimeout(() => reject(new Error("query timeout")), 100);
          });
        });
        
        await expect(adapter.query(User, { id: "timeout-test" })).rejects.toThrow("query timeout");
      });
      
      test("should handle session cleanup verification", async () => {
        const closeSpy = jest.spyOn(mockSession, 'close');
        
        // Perform multiple operations
        await adapter.query(User, { id: "cleanup1" });
        await adapter.query(User, { id: "cleanup2" });
        await adapter.query(User, { id: "cleanup3" });
        
        // Verify all sessions were properly closed
        expect(closeSpy).toHaveBeenCalledTimes(3);
      });
      
      test("should handle Neo4j heap exhaustion", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Java heap space"));
        
        await expect(adapter.query(User, { id: "heap-test" })).rejects.toThrow("Java heap space");
      });
      
    });
    
    describe("Optimization Edge Cases", () => {
      
      test("should handle query plan failures", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Unable to create execution plan"));
        
        await expect(adapter.query(User, { complexCriteria: "value" })).rejects.toThrow("Unable to create execution plan");
      });
      
      test("should handle index usage verification", async () => {
        // Mock query execution with index information
        const explainResult = {
          records: [{
            get: () => ({
              operatorType: "NodeIndexSeek",
              identifiers: ["n"],
              dbHits: 1
            })
          }],
          summary: {
            counters: { updates: () => ({}) },
            resultAvailableAfter: 1.5,
            resultConsumedAfter: 2.0,
            query: { text: "EXPLAIN MATCH (n:User) WHERE n.email = $email RETURN n", parameters: { email: "test@example.com" } }
          }
        };
        
        mockSession.run.mockResolvedValueOnce(explainResult);
        
        const result = await adapter.runNativeQuery("EXPLAIN MATCH (n:User) WHERE n.email = $email RETURN n", { email: "test@example.com" }) as any;
        
        expect(result.records[0].operatorType).toBe("NodeIndexSeek");
      });
      
      test("should handle bulk operation limits", async () => {
        // Create a large number of entities to save
        const users = Array.from({ length: 1000 }, (_, i) => {
          const user = new User();
          user.id = `bulk${i}`;
          user.name = `Bulk User ${i}`;
          user.email = `bulk${i}@example.com`;
          return user;
        });
        
        // Mock bulk operation that hits limits
        mockTransaction.run.mockRejectedValueOnce(new Error("too many parameters"));
        
        // Attempt to save all users in one transaction (should fail)
        for (const user of users) {
          await expect(adapter.save(user)).rejects.toThrow("too many parameters");
          break; // Only test first one
        }
      });
      
      test("should handle session reuse patterns", async () => {
        const sessionSpy = jest.spyOn(mockDriver, 'session');
        
        // Perform multiple rapid operations
        const operations = [
          adapter.query(User, { id: "reuse1" }),
          adapter.query(User, { id: "reuse2" }),
          adapter.query(User, { id: "reuse3" }),
          adapter.query(User, { id: "reuse4" }),
          adapter.query(User, { id: "reuse5" })
        ];
        
        await Promise.all(operations);
        
        // Verify sessions were requested (reuse is handled by driver)
        expect(sessionSpy).toHaveBeenCalledTimes(5);
      });
      
      test("should handle Neo4j version compatibility", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("Feature not supported in Neo4j version"));
        
        await expect(adapter.runNativeQuery("CALL db.labels()")).rejects.toThrow("Feature not supported in Neo4j version");
      });
      
      test("should handle APOC procedure failures", async () => {
        mockSession.run.mockRejectedValueOnce(new Error("APOC procedure not found"));
        
        await expect(adapter.runNativeQuery("CALL apoc.periodic.iterate('MATCH (n) RETURN n', 'SET n.processed = true', {})")).rejects.toThrow("APOC procedure not found");
      });
      
    });
    
  });
  
});