import { BinaryTreeNode, BST, BSTNode, Range } from '../../../../src';
import { isDebugTest, isTestStackOverflow, SYSTEM_MAX_CALL_STACK } from '../../../config';

const isDebug = isDebugTest;

describe('BST operations test', () => {
  it('should add undefined and null', () => {
    const bst = new BST<number, string>();
    const isAddUndefined = bst.add(undefined);
    expect(isAddUndefined).toBe(false);
    expect(bst.get(undefined)).toBe(undefined);
    const isAddNull = bst.add(null);
    expect(isAddNull).toBe(false);
    expect(bst.get(null)).toBe(undefined);
    const isAdd0 = bst.add(0, '0');
    expect(isAdd0).toBe(true);
    expect(bst.get(0)).toBe('0');
  });

  it('should addMany undefined and null', () => {
    const bst = new BST<number, string>();
    const addManyWithUndefined = bst.addMany([1, undefined, 3]);
    expect(addManyWithUndefined).toEqual([true, false, true]);
    expect(bst.get(undefined)).toBe(undefined);
    const addManyWithNull = bst.addMany([1, null, 3, 4]);
    expect(addManyWithNull).toEqual([true, false, true, true]);
    const addManyEntriesWithNull = bst.addMany([
      [1, '1'],
      [null, 'null'],
      [3, '3'],
      [4, '4']
    ]);
    expect(addManyEntriesWithNull).toEqual([true, false, true, true]);
    expect(bst.get(null)).toBe(undefined);
    const node0 = bst.add(0, '0');
    expect(node0).toBe(true);
    expect(bst.get(0)).toBe('0');
  });

  it('should perform various operations on a Binary Search Tree with numeric values', () => {
    const bst = new BST<number, number>();
    expect(bst).toBeInstanceOf(BST);
    bst.add([11, 11]);
    bst.add([3, 3]);
    const idsAndValues: [number, number][] = [
      [15, 15],
      [1, 1],
      [8, 8],
      [13, 13],
      [16, 16],
      [2, 2],
      [6, 6],
      [9, 9],
      [12, 12],
      [14, 14],
      [4, 4],
      [7, 7],
      [10, 10],
      [5, 5]
    ];
    bst.addMany(idsAndValues, [], false);
    expect(bst.root).toBeInstanceOf(BSTNode);

    if (bst.root) expect(bst.root.key).toBe(11);

    expect(bst.size).toBe(16);

    expect(bst.has(6)).toBe(true);

    const node6 = bst.getNode(6);
    expect(node6 && bst.getHeight(6)).toBe(2);
    expect(node6 && bst.getDepth(6)).toBe(3);

    const nodeId10 = bst.getNode(10);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = bst.getNode(node => node.key === 9);
    expect(nodeVal9?.key).toBe(9);

    const leftMost = bst.getLeftMost();
    expect(leftMost).toBe(1);

    expect(bst.isBST()).toBe(true);

    const node15 = bst.getNode(15);
    const minNodeBySpecificNode = node15 && bst.getLeftMost(node => node, node15);
    expect(minNodeBySpecificNode?.key).toBe(12);

    const nodes = bst.getNodes(node => node.key === 15);
    expect(nodes.map(node => node.key)).toEqual([15]);

    let subTreeSum = 0;
    if (node15) bst.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
    expect(subTreeSum).toBe(70);

    let lesserSum = 0;
    bst.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10);
    expect(lesserSum).toBe(45);

    expect(node15).toBeInstanceOf(BSTNode);

    const node11 = bst.getNode(11);
    expect(node11).toBeInstanceOf(BSTNode);

    const dfsInorderNodes = bst.dfs(node => node, 'IN');
    expect(dfsInorderNodes[0].key).toBe(1);
    expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);

    bst.perfectlyBalance();
    expect(bst.isPerfectlyBalanced()).toBe(true);

    const bfsNodesAfterBalanced: BSTNode<number>[] = [];
    bst.bfs(node => bfsNodesAfterBalanced.push(node));
    expect(bfsNodesAfterBalanced[0].key).toBe(8);
    expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);

    const removed11 = bst.delete(11);
    expect(removed11).toBeInstanceOf(Array);
    expect(removed11[0]).toBeDefined();
    expect(removed11[0].deleted).toBeDefined();

    if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);

    expect(bst.isAVLBalanced()).toBe(true);

    expect(bst.getHeight(15)).toBe(1);

    const removed1 = bst.delete(1);
    expect(removed1).toBeInstanceOf(Array);
    expect(removed1[0]).toBeDefined();
    expect(removed1[0].deleted).toBeDefined();
    if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);

    expect(bst.isAVLBalanced()).toBe(true);

    expect(bst.getHeight()).toBe(4);

    const removed4 = bst.delete(4);
    expect(removed4).toBeInstanceOf(Array);
    expect(removed4[0]).toBeDefined();
    expect(removed4[0].deleted).toBeDefined();
    if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(4);

    const removed10 = bst.delete(10);
    expect(removed10).toBeInstanceOf(Array);
    expect(removed10[0]).toBeDefined();
    expect(removed10[0].deleted).toBeDefined();
    if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(4);

    const removed15 = bst.delete(15);
    expect(removed15).toBeInstanceOf(Array);
    expect(removed15[0]).toBeDefined();
    expect(removed15[0].deleted).toBeDefined();
    if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);

    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed5 = bst.delete(5);
    expect(removed5).toBeInstanceOf(Array);
    expect(removed5[0]).toBeDefined();
    expect(removed5[0].deleted).toBeDefined();
    if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);

    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed13 = bst.delete(13);
    expect(removed13).toBeInstanceOf(Array);
    expect(removed13[0]).toBeDefined();
    expect(removed13[0].deleted).toBeDefined();
    if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed3 = bst.delete(3);
    expect(removed3).toBeInstanceOf(Array);
    expect(removed3[0]).toBeDefined();
    expect(removed3[0].deleted).toBeDefined();
    if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed8 = bst.delete(8);
    expect(removed8).toBeInstanceOf(Array);
    expect(removed8[0]).toBeDefined();
    expect(removed8[0].deleted).toBeDefined();
    if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed6 = bst.delete(6);
    expect(removed6).toBeInstanceOf(Array);
    expect(removed6[0]).toBeDefined();
    expect(removed6[0].deleted).toBeDefined();
    if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
    expect(bst.delete(6).length).toBe(0);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed7 = bst.delete(7);
    expect(removed7).toBeInstanceOf(Array);
    expect(removed7[0]).toBeDefined();
    expect(removed7[0].deleted).toBeDefined();
    if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed9 = bst.delete(9);
    expect(removed9).toBeInstanceOf(Array);
    expect(removed9[0]).toBeDefined();
    expect(removed9[0].deleted).toBeDefined();
    if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed14 = bst.delete(14);
    expect(removed14).toBeInstanceOf(Array);
    expect(removed14[0]).toBeDefined();
    expect(removed14[0].deleted).toBeDefined();
    if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(2);

    expect(bst.isAVLBalanced()).toBe(false);

    const bfsIDs: number[] = [];
    bst.bfs(node => bfsIDs.push(node.key));
    expect(bfsIDs[0]).toBe(2);
    expect(bfsIDs[1]).toBe(12);
    expect(bfsIDs[2]).toBe(16);

    const bfsNodes: BSTNode<number>[] = [];
    bst.bfs(node => bfsNodes.push(node));
    expect(bfsNodes[0].key).toBe(2);
    expect(bfsNodes[1].key).toBe(12);
    expect(bfsNodes[2].key).toBe(16);
    bst.clear();
    expect(bst.perfectlyBalance()).toBe(false);
    expect(bst.isAVLBalanced()).toBe(true);
  });

  it('should perform various operations on a Binary Search Tree with object values', () => {
    const objBST = new BST<number, { name: string; age: number }>();
    expect(objBST).toBeInstanceOf(BST);
    objBST.add([11, { name: '11', age: 11 }]);
    objBST.add([3, { name: '3', age: 3 }]);

    objBST.addMany(
      [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5],
      [
        { name: 'Alice', age: 15 },
        { name: 'Bob', age: 1 },
        { name: 'Charlie', age: 8 },
        { name: 'David', age: 13 },
        { name: 'Emma', age: 16 },
        { name: 'Frank', age: 2 },
        { name: 'Grace', age: 6 },
        { name: 'Hannah', age: 9 },
        { name: 'Isaac', age: 12 },
        { name: 'Jack', age: 14 },
        { name: 'Katie', age: 4 },
        { name: 'Liam', age: 7 },
        { name: 'Mia', age: 10 },
        { name: 'Noah', age: 5 }
      ],
      false
    );

    expect(objBST.root).toBeInstanceOf(BSTNode);

    if (objBST.root) expect(objBST.root.key).toBe(11);

    expect(objBST.has(6)).toBe(true);

    const node6 = objBST.getNode(6);
    expect(node6 && objBST.getHeight(node6)).toBe(2);
    expect(node6 && objBST.getDepth(node6)).toBe(3);

    const nodeId10 = objBST.getNode(10);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = objBST.getNode(9);
    expect(nodeVal9?.key).toBe(9);

    const leftMost = objBST.getLeftMost();
    expect(leftMost).toBe(1);

    const node15 = objBST.getNode(15);
    expect(objBST.get(node15)).toEqual({
      name: 'Alice',
      age: 15
    });
    const minNodeBySpecificNode = node15 && objBST.getLeftMost(node => node, node15);
    expect(minNodeBySpecificNode?.key).toBe(12);

    let subTreeSum = 0;
    if (node15) objBST.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
    expect(subTreeSum).toBe(70);

    let lesserSum = 0;
    objBST.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10);
    expect(lesserSum).toBe(45);

    expect(node15).toBeInstanceOf(BSTNode);

    const node11 = objBST.getNode(11);
    expect(node11).toBeInstanceOf(BSTNode);

    const dfsInorderNodes = objBST.dfs(node => node, 'IN');
    expect(dfsInorderNodes[0].key).toBe(1);
    expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);

    objBST.perfectlyBalance();
    expect(objBST.isPerfectlyBalanced()).toBe(true);

    const bfsNodesAfterBalanced: BSTNode<number, { name: string; age: number }>[] = [];
    objBST.bfs(node => bfsNodesAfterBalanced.push(node));
    expect(bfsNodesAfterBalanced[0].key).toBe(8);
    expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);

    const removed11 = objBST.delete(11);
    expect(removed11).toBeInstanceOf(Array);
    expect(removed11[0]).toBeDefined();
    expect(removed11[0].deleted).toBeDefined();

    if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);

    expect(objBST.isAVLBalanced()).toBe(true);

    expect(node15 && objBST.getHeight(node15)).toBe(2);

    const removed1 = objBST.delete(1);
    expect(removed1).toBeInstanceOf(Array);
    expect(removed1[0]).toBeDefined();
    expect(removed1[0].deleted).toBeDefined();
    if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);

    expect(objBST.isAVLBalanced()).toBe(true);

    expect(objBST.getHeight()).toBe(4);

    const removed4 = objBST.delete(4);
    expect(removed4).toBeInstanceOf(Array);
    expect(removed4[0]).toBeDefined();
    expect(removed4[0].deleted).toBeDefined();
    if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(4);

    const removed10 = objBST.delete(10);
    expect(removed10).toBeInstanceOf(Array);
    expect(removed10[0]).toBeDefined();
    expect(removed10[0].deleted).toBeDefined();
    if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(4);

    const removed15 = objBST.delete(15);
    expect(removed15).toBeInstanceOf(Array);
    expect(removed15[0]).toBeDefined();
    expect(removed15[0].deleted).toBeDefined();
    if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);

    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed5 = objBST.delete(5);
    expect(removed5).toBeInstanceOf(Array);
    expect(removed5[0]).toBeDefined();
    expect(removed5[0].deleted).toBeDefined();
    if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);

    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed13 = objBST.delete(13);
    expect(removed13).toBeInstanceOf(Array);
    expect(removed13[0]).toBeDefined();
    expect(removed13[0].deleted).toBeDefined();
    if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed3 = objBST.delete(3);
    expect(removed3).toBeInstanceOf(Array);
    expect(removed3[0]).toBeDefined();
    expect(removed3[0].deleted).toBeDefined();
    if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed8 = objBST.delete(8);
    expect(removed8).toBeInstanceOf(Array);
    expect(removed8[0]).toBeDefined();
    expect(removed8[0].deleted).toBeDefined();
    if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed6 = objBST.delete(6);
    expect(removed6).toBeInstanceOf(Array);
    expect(removed6[0]).toBeDefined();
    expect(removed6[0].deleted).toBeDefined();
    if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
    expect(objBST.delete(6).length).toBe(0);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed7 = objBST.delete(7);
    expect(removed7).toBeInstanceOf(Array);
    expect(removed7[0]).toBeDefined();
    expect(removed7[0].deleted).toBeDefined();
    if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed9 = objBST.delete(9);
    expect(removed9).toBeInstanceOf(Array);
    expect(removed9[0]).toBeDefined();
    expect(removed9[0].deleted).toBeDefined();
    if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed14 = objBST.delete(14);
    expect(removed14).toBeInstanceOf(Array);
    expect(removed14[0]).toBeDefined();
    expect(removed14[0].deleted).toBeDefined();
    if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(2);

    expect(objBST.isAVLBalanced()).toBe(false);

    const bfsIDs: number[] = [];
    objBST.bfs(node => bfsIDs.push(node.key));
    expect(bfsIDs[0]).toBe(2);
    expect(bfsIDs[1]).toBe(12);
    expect(bfsIDs[2]).toBe(16);

    const bfsNodes: BSTNode<number, { name: string; age: number }>[] = [];
    objBST.bfs(node => bfsNodes.push(node));
    expect(bfsNodes[0].key).toBe(2);
    expect(bfsNodes[1].key).toBe(12);
    expect(bfsNodes[2].key).toBe(16);
  });

  // it('should keyValueNodeEntryRawToNodeAndValue', () => {
  //   const bst = new BST<number>();
  //   const node0 = bst.keyValueNodeEntryRawToNodeAndValue(0);
  //   expect(node0).toEqual([
  //     {
  //       _left: undefined,
  //       _right: undefined,
  //       key: 0,
  //       parent: undefined,
  //       value: undefined
  //     },
  //     undefined
  //   ]);
  //
  //   const nodeUndefined = bst.keyValueNodeEntryRawToNodeAndValue(undefined);
  //   expect(nodeUndefined).toEqual([undefined, undefined]);
  //
  //   const nodeNull = bst.keyValueNodeEntryRawToNodeAndValue(null);
  //   expect(nodeNull).toEqual([undefined, undefined]);
  // });

  it('should replace value', () => {
    const tree = new BST<number, string>([4, 5, [1, '1'], 2, 3], { isMapMode: false });
    expect(tree.get(1)).toBe('1');
    expect(tree.getNode(1)?.value).toBe('1');
    tree.add(1, 'a');
    expect(tree.get(1)).toBe('a');
    tree.add([1, 'b']);
    expect(tree.getNode(1)?.value).toBe('b');
    expect(tree.get(1)).toBe('b');
    const treeMap = new BST<number>([4, 5, [1, '1'], 2, 3]);
    expect(treeMap.get(1)).toBe('1');
    expect(treeMap.getNode(1)?.value).toBe(undefined);
    treeMap.add(1, 'a');
    expect(treeMap.get(1)).toBe('a');
    treeMap.add([1, 'b']);
    expect(treeMap.getNode(1)?.value).toBe(undefined);
    expect(treeMap.get(1)).toBe('b');
  });

  it('should search in range', () => {
    const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
    expect(bst.rangeSearch([4, 12])).toEqual([5, 7, 10, 12]);
    expect(() => bst.rangeSearch([12, 4])).toThrow('low must be less than or equal to high');
    expect(bst.rangeSearch([12, 12])).toEqual([12]);
  });
});

describe('BST operations test recursively', () => {
  it('should perform various operations on a Binary Search Tree with numeric values', () => {
    const bst = new BST<number>([], {
      iterationType: 'RECURSIVE'
    });
    expect(bst).toBeInstanceOf(BST);
    bst.add([11, 11]);
    bst.add([3, 3]);
    const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
    bst.addMany(idsAndValues, undefined, false);
    expect(bst.root).toBeInstanceOf(BSTNode);

    if (bst.root) expect(bst.root.key).toBe(11);

    expect(bst.size).toBe(16);

    expect(bst.has(6)).toBe(true);

    const node6 = bst.getNode(6);
    expect(node6 && bst.getHeight(6)).toBe(2);
    expect(node6 && bst.getDepth(6)).toBe(3);

    const nodeId10 = bst.getNode(10);
    expect(bst.get(10)).toBe(undefined);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = bst.getNode(node => node.value === 9);
    expect(bst.get(nodeVal9?.key)).toBe(undefined);

    const leftMost = bst.getLeftMost();
    expect(leftMost).toBe(1);

    const node15 = bst.getNode(15);
    const minNodeBySpecificNode = node15 && bst.getLeftMost(node => node, node15);
    expect(minNodeBySpecificNode?.key).toBe(12);

    let subTreeSum = 0;
    if (node15) bst.dfs(node => (subTreeSum += node.key), 'PRE', false, 15);
    expect(subTreeSum).toBe(70);

    let lesserSum = 0;
    bst.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10);
    expect(lesserSum).toBe(45);

    expect(node15).toBeInstanceOf(BSTNode);

    const node11 = bst.getNode(11);
    expect(node11).toBeInstanceOf(BSTNode);

    const dfsInorderNodes = bst.dfs(node => node, 'IN');
    expect(dfsInorderNodes[0].key).toBe(1);
    expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);

    bst.perfectlyBalance();
    expect(bst.isPerfectlyBalanced()).toBe(true);

    const bfsNodesAfterBalanced: BSTNode<number>[] = [];
    bst.bfs(node => bfsNodesAfterBalanced.push(node));
    expect(bfsNodesAfterBalanced[0].key).toBe(8);
    expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);

    const removed11 = bst.delete(11);
    expect(removed11).toBeInstanceOf(Array);
    expect(removed11[0]).toBeDefined();
    expect(removed11[0].deleted).toBeDefined();

    if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);

    expect(bst.isAVLBalanced()).toBe(true);

    expect(bst.getHeight(15)).toBe(1);

    const removed1 = bst.delete(1);
    expect(removed1).toBeInstanceOf(Array);
    expect(removed1[0]).toBeDefined();
    expect(removed1[0].deleted).toBeDefined();
    if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);

    expect(bst.isAVLBalanced()).toBe(true);

    expect(bst.getHeight()).toBe(4);

    const removed4 = bst.delete(4);
    expect(removed4).toBeInstanceOf(Array);
    expect(removed4[0]).toBeDefined();
    expect(removed4[0].deleted).toBeDefined();
    if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(4);

    const removed10 = bst.delete(10);
    expect(removed10).toBeInstanceOf(Array);
    expect(removed10[0]).toBeDefined();
    expect(removed10[0].deleted).toBeDefined();
    if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(4);

    const removed15 = bst.delete(15);
    expect(removed15).toBeInstanceOf(Array);
    expect(removed15[0]).toBeDefined();
    expect(removed15[0].deleted).toBeDefined();
    if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);

    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed5 = bst.delete(5);
    expect(removed5).toBeInstanceOf(Array);
    expect(removed5[0]).toBeDefined();
    expect(removed5[0].deleted).toBeDefined();
    if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);

    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed13 = bst.delete(13);
    expect(removed13).toBeInstanceOf(Array);
    expect(removed13[0]).toBeDefined();
    expect(removed13[0].deleted).toBeDefined();
    if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed3 = bst.delete(3);
    expect(removed3).toBeInstanceOf(Array);
    expect(removed3[0]).toBeDefined();
    expect(removed3[0].deleted).toBeDefined();
    if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed8 = bst.delete(8);
    expect(removed8).toBeInstanceOf(Array);
    expect(removed8[0]).toBeDefined();
    expect(removed8[0].deleted).toBeDefined();
    if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
    expect(bst.isAVLBalanced()).toBe(true);
    expect(bst.getHeight()).toBe(3);

    const removed6 = bst.delete(6);
    expect(removed6).toBeInstanceOf(Array);
    expect(removed6[0]).toBeDefined();
    expect(removed6[0].deleted).toBeDefined();
    if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
    expect(bst.delete(6).length).toBe(0);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed7 = bst.delete(7);
    expect(removed7).toBeInstanceOf(Array);
    expect(removed7[0]).toBeDefined();
    expect(removed7[0].deleted).toBeDefined();
    if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed9 = bst.delete(9);
    expect(removed9).toBeInstanceOf(Array);
    expect(removed9[0]).toBeDefined();
    expect(removed9[0].deleted).toBeDefined();
    if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(3);

    const removed14 = bst.delete(14);
    expect(removed14).toBeInstanceOf(Array);
    expect(removed14[0]).toBeDefined();
    expect(removed14[0].deleted).toBeDefined();
    if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
    expect(bst.isAVLBalanced()).toBe(false);
    expect(bst.getHeight()).toBe(2);

    expect(bst.isAVLBalanced()).toBe(false);

    const bfsIDs: number[] = [];
    bst.bfs(node => bfsIDs.push(node.key));
    expect(bfsIDs[0]).toBe(2);
    expect(bfsIDs[1]).toBe(12);
    expect(bfsIDs[2]).toBe(16);

    const bfsNodes: BSTNode<number>[] = [];
    bst.bfs(node => bfsNodes.push(node));
    expect(bfsNodes[0].key).toBe(2);
    expect(bfsNodes[1].key).toBe(12);
    expect(bfsNodes[2].key).toBe(16);
  });

  it('should perform various operations on a Binary Search Tree with object values', () => {
    const objBST = new BST<number, { key: number; keyA: number }>();
    expect(objBST).toBeInstanceOf(BST);
    objBST.add([11, { key: 11, keyA: 11 }]);
    objBST.add([3, { key: 3, keyA: 3 }]);
    const entries: [number, { key: number; keyA: number }][] = [
      [15, { key: 15, keyA: 15 }],
      [1, { key: 1, keyA: 1 }],
      [8, { key: 8, keyA: 8 }],
      [13, { key: 13, keyA: 13 }],
      [16, { key: 16, keyA: 16 }],
      [2, { key: 2, keyA: 2 }],
      [6, { key: 6, keyA: 6 }],
      [9, { key: 9, keyA: 9 }],
      [12, { key: 12, keyA: 12 }],
      [14, { key: 14, keyA: 14 }],
      [4, { key: 4, keyA: 4 }],
      [7, { key: 7, keyA: 7 }],
      [10, { key: 10, keyA: 10 }],
      [5, { key: 5, keyA: 5 }]
    ];

    objBST.addMany(entries, undefined, false);

    expect(objBST.root).toBeInstanceOf(BSTNode);

    if (objBST.root) expect(objBST.root.key).toBe(11);

    expect(objBST.has(6)).toBe(true);

    const node6 = objBST.getNode(6);
    expect(objBST.get(6)).toEqual({
      key: 6,
      keyA: 6
    });
    expect(node6 && objBST.getHeight(node6)).toBe(2);
    expect(node6 && objBST.getDepth(node6)).toBe(3);

    const nodeId10 = objBST.getNode(10);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = objBST.getNode(9);
    expect(nodeVal9?.key).toBe(9);

    const leftMost = objBST.getLeftMost();
    expect(leftMost).toBe(1);

    const node15 = objBST.getNode(15);
    expect(objBST.get(node15)).toEqual({
      key: 15,
      keyA: 15
    });
    const minNodeBySpecificNode = node15 && objBST.getLeftMost(node => node, node15);
    expect(minNodeBySpecificNode?.key).toBe(12);

    let subTreeSum = 0;
    if (node15) objBST.dfs(node => (subTreeSum += node.key), 'PRE', false, node15);
    expect(subTreeSum).toBe(70);

    let lesserSum = 0;
    objBST.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10);
    expect(lesserSum).toBe(45);

    expect(node15).toBeInstanceOf(BSTNode);

    const node11 = objBST.getNode(11);
    expect(node11).toBeInstanceOf(BSTNode);

    const dfsInorderNodes = objBST.dfs(node => node, 'IN');
    expect(dfsInorderNodes[0].key).toBe(1);
    expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);

    objBST.perfectlyBalance();
    expect(objBST.isPerfectlyBalanced()).toBe(true);

    const bfsNodesAfterBalanced: BSTNode<number, { key: number; keyA: number }>[] = [];
    objBST.bfs(node => bfsNodesAfterBalanced.push(node));
    expect(bfsNodesAfterBalanced[0].key).toBe(8);
    expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);

    const removed11 = objBST.delete(11);
    expect(removed11).toBeInstanceOf(Array);
    expect(removed11[0]).toBeDefined();
    expect(removed11[0].deleted).toBeDefined();

    if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);

    expect(objBST.isAVLBalanced()).toBe(true);

    expect(node15 && objBST.getHeight(node15)).toBe(2);

    const removed1 = objBST.delete(1);
    expect(removed1).toBeInstanceOf(Array);
    expect(removed1[0]).toBeDefined();
    expect(removed1[0].deleted).toBeDefined();
    if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);

    expect(objBST.isAVLBalanced()).toBe(true);

    expect(objBST.getHeight()).toBe(4);

    const removed4 = objBST.delete(4);
    expect(removed4).toBeInstanceOf(Array);
    expect(removed4[0]).toBeDefined();
    expect(removed4[0].deleted).toBeDefined();
    if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(4);

    const removed10 = objBST.delete(10);
    expect(removed10).toBeInstanceOf(Array);
    expect(removed10[0]).toBeDefined();
    expect(removed10[0].deleted).toBeDefined();
    if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(4);

    const removed15 = objBST.delete(15);
    expect(removed15).toBeInstanceOf(Array);
    expect(removed15[0]).toBeDefined();
    expect(removed15[0].deleted).toBeDefined();
    if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);

    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed5 = objBST.delete(5);
    expect(removed5).toBeInstanceOf(Array);
    expect(removed5[0]).toBeDefined();
    expect(removed5[0].deleted).toBeDefined();
    if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);

    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed13 = objBST.delete(13);
    expect(removed13).toBeInstanceOf(Array);
    expect(removed13[0]).toBeDefined();
    expect(removed13[0].deleted).toBeDefined();
    if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed3 = objBST.delete(3);
    expect(removed3).toBeInstanceOf(Array);
    expect(removed3[0]).toBeDefined();
    expect(removed3[0].deleted).toBeDefined();
    if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed8 = objBST.delete(8);
    expect(removed8).toBeInstanceOf(Array);
    expect(removed8[0]).toBeDefined();
    expect(removed8[0].deleted).toBeDefined();
    if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
    expect(objBST.isAVLBalanced()).toBe(true);
    expect(objBST.getHeight()).toBe(3);

    const removed6 = objBST.delete(6);
    expect(removed6).toBeInstanceOf(Array);
    expect(removed6[0]).toBeDefined();
    expect(removed6[0].deleted).toBeDefined();
    if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
    expect(objBST.delete(6).length).toBe(0);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed7 = objBST.delete(7);
    expect(removed7).toBeInstanceOf(Array);
    expect(removed7[0]).toBeDefined();
    expect(removed7[0].deleted).toBeDefined();
    if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed9 = objBST.delete(9);
    expect(removed9).toBeInstanceOf(Array);
    expect(removed9[0]).toBeDefined();
    expect(removed9[0].deleted).toBeDefined();
    if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(3);

    const removed14 = objBST.delete(14);
    expect(removed14).toBeInstanceOf(Array);
    expect(removed14[0]).toBeDefined();
    expect(removed14[0].deleted).toBeDefined();
    if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
    expect(objBST.isAVLBalanced()).toBe(false);
    expect(objBST.getHeight()).toBe(2);

    expect(objBST.isAVLBalanced()).toBe(false);

    const bfsIDs: number[] = [];
    objBST.bfs(node => bfsIDs.push(node.key));
    expect(bfsIDs[0]).toBe(2);
    expect(bfsIDs[1]).toBe(12);
    expect(bfsIDs[2]).toBe(16);

    const bfsNodes: BSTNode<number, { key: number; keyA: number }>[] = [];
    objBST.bfs(node => bfsNodes.push(node));
    expect(bfsNodes[0].key).toBe(2);
    expect(bfsNodes[1].key).toBe(12);
    expect(bfsNodes[2].key).toBe(16);
  });

  it('should delete', () => {
    const numBST = new BST<number>();
    numBST.addMany([2, 4, 5, 3, 1]);
    expect(numBST.size).toBe(5);
    numBST.delete(1);
    expect(numBST.size).toBe(4);

    numBST.delete(2);
    numBST.delete(3);
    numBST.delete(4);
    numBST.delete(5);
    expect(numBST.size).toBe(0);
    numBST.delete(5);
    expect(numBST.size).toBe(0);
  });

  it('should listLevels', () => {
    const bst = new BST<number>();
    bst.addMany([2, 4, 5, 3, 1]);
    expect(bst.size).toBe(5);
    bst.delete(1);
    bst.delete(5);
    const levelKeys = bst.listLevels();
    expect(levelKeys).toEqual([[3], [2, 4]]);
  });

  it('should lesserOrGreaterTraverse', () => {
    const bst = new BST<number>();
    const levelKeys = bst.lesserOrGreaterTraverse();
    expect(levelKeys).toEqual([]);
    bst.addMany([2, 4, 5, 3, 1]);
    expect(bst.size).toBe(5);
    bst.delete(1);
    bst.delete(5);
    const levelKeys1 = bst.lesserOrGreaterTraverse();
    expect(levelKeys1).toEqual([2]);
  });

  it('should the clone method', () => {
    function checkTreeStructure(bst: BST<string, number>) {
      expect(bst.size).toBe(4);
      expect(bst.root?.key).toBe('2');
      expect(bst.root?.left?.key).toBe('1');
      expect(bst.root?.left?.left?.key).toBe(undefined);
      expect(bst.root?.left?.right?.key).toBe(undefined);
      expect(bst.root?.right?.key).toBe('4');
      expect(bst.root?.right?.left?.key).toBe(undefined);
      expect(bst.root?.right?.right?.key).toBe('5');
    }

    const bst = new BST<string, number>();
    bst.addMany([
      ['2', 2],
      ['4', 4],
      ['5', 5],
      ['3', 3],
      ['1', 1]
    ]);
    expect(bst.size).toBe(5);
    expect(bst.root?.key).toBe('3');
    expect(bst.root?.left?.key).toBe('1');
    expect(bst.root?.left?.left?.key).toBe(undefined);
    expect(bst.root?.left?.right?.key).toBe('2');
    expect(bst.root?.right?.key).toBe('4');
    expect(bst.root?.right?.left?.key).toBe(undefined);
    expect(bst.root?.right?.right?.key).toBe('5');
    bst.delete('3');
    checkTreeStructure(bst);
    const cloned = bst.clone();
    checkTreeStructure(cloned);
    bst.delete('2');
    bst.delete('1');
    bst.delete('4');
    bst.delete('5');
    expect(bst.size).toBe(0);

    cloned.delete('1');
    expect(bst.size).toBe(0);
    expect(cloned.size).toBe(3);
    cloned.delete('2');
    cloned.delete('3');
    cloned.delete('4');
    cloned.delete('5');
    expect(cloned.size).toBe(0);
  });

  if (isTestStackOverflow) {
    it('should getLeftMost', () => {
      const bst = new BST<number>([], { specifyComparable: key => key });
      for (let i = 1; i <= SYSTEM_MAX_CALL_STACK; i++) bst.add(i);

      expect(() => {
        const leftMost = bst.getLeftMost(node => node, bst.root, 'RECURSIVE');
        expect(leftMost?.key).toEqual(SYSTEM_MAX_CALL_STACK);
      }).toThrow('Maximum call stack size exceeded');

      const leftMost = bst.getLeftMost(node => node, bst.root, 'ITERATIVE');
      expect(leftMost?.key).toEqual(SYSTEM_MAX_CALL_STACK);
    });

    it('should getRightMost', () => {
      const bst = new BST<number>();
      for (let i = 1; i <= SYSTEM_MAX_CALL_STACK; i++) bst.add(i);

      expect(() => {
        const rightMost = bst.getRightMost(node => node, bst.root, 'RECURSIVE');
        expect(rightMost?.key).toEqual(SYSTEM_MAX_CALL_STACK);
      }).toThrow('Maximum call stack size exceeded');
      const rightMost = bst.getRightMost(node => node, bst.root, 'ITERATIVE');
      expect(rightMost?.key).toEqual(SYSTEM_MAX_CALL_STACK);
    });
  }
});

describe('BST isBST', function () {
  it('isBST', () => {
    const bst = new BST<number, number>();
    bst.addMany([1, 2, 3, 9, 8, 5, 6, 7, 4]);
    expect(bst.isBST()).toBe(true);
  });

  it('isBST when variant is Max', () => {
    const bst = new BST<number, number>([1, 2, 3, 9, 8, 5, 6, 7, 4], {
      isReverse: true
    });
    bst.addMany([1, 2, 3, 9, 8, 5, 6, 7, 4]);
    expect(bst.isBST()).toBe(true);
  });
});

describe('BST Performance test', function () {
  const bst = new BST<number, number>();
  const inputSize = 10000; // Adjust input sizes as needed

  beforeEach(() => {
    bst.clear();
  });

  it(`Observe the time consumption of BST.dfs be good`, function () {
    const startDFS = performance.now();
    const dfs = bst.dfs(node => node);
    if (isDebug) console.log('---bfs', performance.now() - startDFS, dfs.length);
  });

  it('Should the time consumption of lesserOrGreaterTraverse fitting O(n log n)', function () {
    const nodes: number[] = [];
    for (let i = 0; i < inputSize; i++) {
      nodes.push(i);
    }
    const start = performance.now();
    bst.addMany(nodes);
    if (isDebug) console.log('---add', performance.now() - start);
    const startL = performance.now();
    bst.lesserOrGreaterTraverse(
      node => {
        node.key -= 1;
      },
      -1,
      inputSize / 2
    );
    if (isDebug) console.log('---lesserOrGreaterTraverse', performance.now() - startL);
  });

  it('Should the time consumption of listLevels fitting well', function () {
    const nodes: number[] = [];
    for (let i = 0; i < inputSize; i++) {
      nodes.push(i);
    }
    const start = performance.now();
    bst.addMany(nodes);
    if (isDebug) console.log('---add', performance.now() - start);
    const startL = performance.now();
    const arr: number[][] = bst.listLevels(node => node.key);
    if (isDebug) console.log('---listLevels', arr);
    if (isDebug) console.log('---listLevels', performance.now() - startL);
  });

  it('should the lastKey of a BST to be the largest key', function () {
    const bst = new BST();
    bst.addMany([9, 8, 7, 3, 1, 2, 5, 4, 6], undefined, false);
    // TODO
    // expect(bst.lastKey()).toBe(9);
  });

  it('should dfs as sub tree traversal, null should be ignored', () => {
    const bst = new BST();
    bst.addMany([4, 2, 6, 1, 3, 5, 7]);
    expect(bst.dfs(node => node.key, 'PRE', false, bst.getNode(6), 'ITERATIVE')).toEqual([6, 5, 7]);
    expect(bst.dfs(node => node.key, 'PRE', false, bst.getNode(6), 'RECURSIVE')).toEqual([6, 5, 7]);
    expect(bst.dfs(node => node?.key ?? undefined, 'PRE', false, bst.getNode(6), 'ITERATIVE')).toEqual([6, 5, 7]);
    expect(bst.dfs(node => node?.key ?? undefined, 'PRE', false, bst.getNode(6), 'RECURSIVE')).toEqual([6, 5, 7]);
  });
});

describe('BST iterative methods test', () => {
  let bst: BST<number, string>;
  beforeEach(() => {
    bst = new BST();
    bst.addMany(
      [
        [1, 'a'],
        [2, 'b'],
        [3, 'c']
      ],
      [],
      false
    );
  });

  it('The node obtained by get Node should match the node type', () => {
    const node3 = bst.getNode(3);
    expect(node3).toBeInstanceOf(BinaryTreeNode);
    expect(node3).toBeInstanceOf(BSTNode);
  });

  it('forEach should iterate over all elements', () => {
    const mockCallback = jest.fn();
    bst.forEach((key, value) => {
      mockCallback(key, value);
    });

    expect(mockCallback.mock.calls.length).toBe(3);
    expect(mockCallback.mock.calls[0]).toEqual([1, 'a']);
    expect(mockCallback.mock.calls[1]).toEqual([2, 'b']);
    expect(mockCallback.mock.calls[2]).toEqual([3, 'c']);
  });

  it('filter should return a new tree with filtered elements', () => {
    const filteredTree = bst.filter(key => key > 1);
    expect(filteredTree.size).toBe(2);
    expect([...filteredTree]).toEqual([
      [2, 'b'],
      [3, 'c']
    ]);
  });

  it('map should return a new tree with modified elements', () => {
    const mappedTree = bst.map((key, value) => [(key * 2).toString(), value]);
    expect(mappedTree.size).toBe(3);
    expect([...mappedTree]).toEqual([
      ['2', 'a'],
      ['4', 'b'],
      ['6', 'c']
    ]);
  });

  it('reduce should accumulate values', () => {
    const sum = bst.reduce((acc, value, key) => acc + key, 0);
    expect(sum).toBe(6);
  });

  it('[Symbol.iterator] should provide an iterator', () => {
    const entries = [];
    for (const entry of bst) {
      entries.push(entry);
    }

    expect(entries.length).toBe(3);
    expect(entries).toEqual([
      [1, 'a'],
      [2, 'b'],
      [3, 'c']
    ]);
  });

  it('should clone work well', () => {
    const cloned = bst.clone();
    expect(cloned.root?.left).toBe(undefined);
    expect(cloned.root?.right?.value).toBe(undefined);
  });

  it('should keys', () => {
    const keys = bst.keys();
    expect([...keys]).toEqual([1, 2, 3]);
  });

  it('should values', () => {
    const values = bst.values();
    expect([...values]).toEqual(['a', 'b', 'c']);
  });

  it('should leaves', () => {
    const leaves = bst.leaves();
    expect(leaves).toEqual([3]);
  });

  it('should collapsed, unbalanced, balanced bst leaves', () => {
    const collapsedToLinkedList = new BST();
    collapsedToLinkedList.addMany(
      [
        [1, 'a'],
        [2, 'b'],
        [3, 'c'],
        [4, 'd'],
        [5, 'e'],
        [6, 'f'],
        [7, 'g'],
        [8, 'h'],
        [9, 'i']
      ],
      [],
      false
    );

    expect(collapsedToLinkedList.leaves()).toEqual([9]);

    const unbalanced = new BST();
    unbalanced.addMany(
      [
        [2, 'b'],
        [1, 'a'],
        [3, 'c'],
        [4, 'd'],
        [5, 'e'],
        [6, 'f'],
        [7, 'g'],
        [8, 'h'],
        [9, 'i']
      ],
      [],
      false
    );

    expect(unbalanced.leaves()).toEqual([1, 9]);

    const balanced = new BST();
    balanced.addMany(
      [
        [2, 'b'],
        [1, 'a'],
        [3, 'c'],
        [4, 'd'],
        [5, 'e'],
        [6, 'f'],
        [7, 'g'],
        [8, 'h'],
        [9, 'i']
      ],
      [],
      true
    );

    expect(balanced.leaves()).toEqual([1, 6, 4, 9]);
    expect(balanced.leaves(node => balanced.get(node))).toEqual(['a', 'f', 'd', 'i']);
  });
});

describe('BST operations not map mode test', () => {
  it('should perform various operations on a Binary Search Tree with numeric values', () => {
    const bst = new BST<number, number>([], { isMapMode: false });
    expect(bst).toBeInstanceOf(BST);
    bst.add([11, 11]);
    bst.add([3, 3]);
    const idsAndValues: [number, number][] = [
      [15, 15],
      [1, 1],
      [8, 8],
      [13, 13],
      [16, 16],
      [2, 2],
      [6, 6],
      [9, 9],
      [12, 12],
      [14, 14],
      [4, 4],
      [7, 7],
      [10, 10],
      [5, 5]
    ];
    bst.addMany(idsAndValues, undefined, false);
    expect(bst.root).toBeInstanceOf(BSTNode);

    if (bst.root) expect(bst.root.key).toBe(11);

    expect(bst.size).toBe(16);

    expect(bst.has(6)).toBe(true);

    const node6 = bst.getNode(6);
    expect(node6 && bst.getHeight(6)).toBe(2);
    expect(node6 && bst.getDepth(6)).toBe(3);

    const nodeId10 = bst.getNode(10);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = bst.getNode(node => node.key === 9);
    expect(nodeVal9?.key).toBe(9);

    const leftMost = bst.getLeftMost();
    expect(leftMost).toBe(1);

    expect(bst.isBST()).toBe(true);

    const node15 = bst.getNode(15);
    const minNodeBySpecificNode = node15 && bst.getLeftMost(node => node, node15);
    expect(minNodeBySpecificNode?.key).toBe(12);

    const nodes = bst.getNodes(node => node.key === 15);
    expect(nodes.map(node => node.key)).toEqual([15]);
  });

  it('should perform various operations on a Binary Search Tree with object values', () => {
    const objBST = new BST<number, { name: string; age: number }>([], { isMapMode: false });
    expect(objBST).toBeInstanceOf(BST);
    objBST.add([11, { name: '11', age: 11 }]);
    objBST.add([3, { name: '3', age: 3 }]);

    objBST.addMany(
      [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5],
      [
        { name: 'Alice', age: 15 },
        { name: 'Bob', age: 1 },
        { name: 'Charlie', age: 8 },
        { name: 'David', age: 13 },
        { name: 'Emma', age: 16 },
        { name: 'Frank', age: 2 },
        { name: 'Grace', age: 6 },
        { name: 'Hannah', age: 9 },
        { name: 'Isaac', age: 12 },
        { name: 'Jack', age: 14 },
        { name: 'Katie', age: 4 },
        { name: 'Liam', age: 7 },
        { name: 'Mia', age: 10 },
        { name: 'Noah', age: 5 }
      ],
      false
    );

    expect(objBST.root).toBeInstanceOf(BSTNode);

    if (objBST.root) expect(objBST.root.key).toBe(11);

    expect(objBST.has(6)).toBe(true);

    const node6 = objBST.getNode(6);
    expect(node6 && objBST.getHeight(node6)).toBe(2);
    expect(node6 && objBST.getDepth(node6)).toBe(3);

    const nodeId10 = objBST.getNode(10);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = objBST.getNode(9);
    expect(nodeVal9?.key).toBe(9);

    const leftMost = objBST.getLeftMost();
    expect(leftMost).toBe(1);

    const node15 = objBST.getNode(15);
    expect(objBST.get(node15)).toEqual({
      name: 'Alice',
      age: 15
    });
  });

  // it('should keyValueNodeEntryRawToNodeAndValue', () => {
  //   const bst = new BST<number>([], { isMapMode: false });
  //   const node0 = bst.keyValueNodeEntryRawToNodeAndValue(0);
  //   expect(node0).toEqual([
  //     {
  //       _left: undefined,
  //       _right: undefined,
  //       key: 0,
  //       parent: undefined,
  //       value: undefined
  //     },
  //     undefined
  //   ]);
  //
  //   const nodeUndefined = bst.keyValueNodeEntryRawToNodeAndValue(undefined);
  //   expect(nodeUndefined).toEqual([undefined, undefined]);
  //
  //   const nodeNull = bst.keyValueNodeEntryRawToNodeAndValue(null);
  //   expect(nodeNull).toEqual([undefined, undefined]);
  // });
});

describe('BST operations not map mode test recursively', () => {
  it('should perform various operations on a Binary Search Tree with numeric values', () => {
    const bst = new BST<number>([], {
      iterationType: 'RECURSIVE',
      isMapMode: false
    });
    expect(bst).toBeInstanceOf(BST);
    bst.add([11, 11]);
    bst.add([3, 3]);
    const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
    bst.addMany(idsAndValues, undefined, false);
    expect(bst.root).toBeInstanceOf(BSTNode);

    if (bst.root) expect(bst.root.key).toBe(11);

    expect(bst.size).toBe(16);

    expect(bst.has(6)).toBe(true);

    const node6 = bst.getNode(6);
    expect(node6 && bst.getHeight(6)).toBe(2);
    expect(node6 && bst.getDepth(6)).toBe(3);

    const nodeId10 = bst.getNode(10);
    expect(bst.get(10)).toBe(undefined);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = bst.getNode(node => node.key === 9);
    expect(bst.get(nodeVal9?.key)).toBe(undefined);
  });

  it('should perform various operations on a Binary Search Tree with object values', () => {
    const objBST = new BST<number, { key: number; keyA: number }>([], { isMapMode: false });
    expect(objBST).toBeInstanceOf(BST);
    objBST.add([11, { key: 11, keyA: 11 }]);
    objBST.add([3, { key: 3, keyA: 3 }]);
    const entries: [number, { key: number; keyA: number }][] = [
      [15, { key: 15, keyA: 15 }],
      [1, { key: 1, keyA: 1 }],
      [8, { key: 8, keyA: 8 }],
      [13, { key: 13, keyA: 13 }],
      [16, { key: 16, keyA: 16 }],
      [2, { key: 2, keyA: 2 }],
      [6, { key: 6, keyA: 6 }],
      [9, { key: 9, keyA: 9 }],
      [12, { key: 12, keyA: 12 }],
      [14, { key: 14, keyA: 14 }],
      [4, { key: 4, keyA: 4 }],
      [7, { key: 7, keyA: 7 }],
      [10, { key: 10, keyA: 10 }],
      [5, { key: 5, keyA: 5 }]
    ];

    objBST.addMany(entries, undefined, false);

    expect(objBST.root).toBeInstanceOf(BSTNode);

    if (objBST.root) expect(objBST.root.key).toBe(11);

    expect(objBST.has(6)).toBe(true);

    const node6 = objBST.getNode(6);
    expect(objBST.get(6)).toEqual({
      key: 6,
      keyA: 6
    });
    expect(node6 && objBST.getHeight(node6)).toBe(2);
    expect(node6 && objBST.getDepth(node6)).toBe(3);

    const nodeId10 = objBST.getNode(10);
    expect(nodeId10?.key).toBe(10);

    const nodeVal9 = objBST.getNode(9);
    expect(nodeVal9?.key).toBe(9);

    const leftMost = objBST.getLeftMost();
    expect(leftMost).toBe(1);

    const node15 = objBST.getNode(15);
    expect(objBST.get(node15)).toEqual({
      key: 15,
      keyA: 15
    });
  });
});

describe('BST iterative methods not map mode test', () => {
  let bst: BST<number, string>;
  beforeEach(() => {
    bst = new BST();
    bst.addMany(
      [
        [1, 'a'],
        [2, 'b'],
        [3, 'c']
      ],
      [],
      false
    );
  });

  it('should clone work well', () => {
    const cloned = bst.clone();
    expect(cloned.root?.left).toBe(undefined);
    expect(cloned.get(cloned.root?.right)).toBe('b');
  });

  it('should collapsed, unbalanced, balanced bst leaves', () => {
    const collapsedToLinkedList = new BST();
    collapsedToLinkedList.addMany(
      [
        [1, 'a'],
        [2, 'b'],
        [3, 'c'],
        [4, 'd'],
        [5, 'e'],
        [6, 'f'],
        [7, 'g'],
        [8, 'h'],
        [9, 'i']
      ],
      [],
      false
    );

    expect(collapsedToLinkedList.leaves()).toEqual([9]);

    const unbalanced = new BST();
    unbalanced.addMany(
      [
        [2, 'b'],
        [1, 'a'],
        [3, 'c'],
        [4, 'd'],
        [5, 'e'],
        [6, 'f'],
        [7, 'g'],
        [8, 'h'],
        [9, 'i']
      ],
      [],
      false
    );

    expect(unbalanced.leaves()).toEqual([1, 9]);

    const balanced = new BST();
    balanced.addMany(
      [
        [2, 'b'],
        [1, 'a'],
        [3, 'c'],
        [4, 'd'],
        [5, 'e'],
        [6, 'f'],
        [7, 'g'],
        [8, 'h'],
        [9, 'i']
      ],
      [],
      true
    );

    expect(balanced.leaves()).toEqual([1, 6, 4, 9]);
    expect(balanced.leaves(node => balanced.get(node?.key))).toEqual(['a', 'f', 'd', 'i']);
  });
});

describe('classic use', () => {
  it('@example Merge 3 sorted datasets', () => {
    const dataset1 = new BST<number, string>([
      [1, 'A'],
      [7, 'G']
    ]);
    const dataset2 = [
      [2, 'B'],
      [6, 'F']
    ];
    const dataset3 = new BST<number, string>([
      [3, 'C'],
      [5, 'E'],
      [4, 'D']
    ]);

    // Merge datasets into a single BinarySearchTree
    const merged = new BST<number, string>(dataset1);
    merged.addMany(dataset2);
    merged.merge(dataset3);

    // Verify merged dataset is in sorted order
    expect([...merged.values()]).toEqual(['A', 'B', 'C', 'D', 'E', 'F', 'G']);
  });

  // Test case for finding elements in a given range
  it('@example Find elements in a range', () => {
    const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
    expect(bst.search(new Range(5, 10))).toEqual([5, 7, 10]);
    expect(bst.rangeSearch([4, 12], node => node.key.toString())).toEqual(['5', '7', '10', '12']);
    expect(bst.search(new Range(4, 12, true, false))).toEqual([5, 7, 10]);
    expect(bst.rangeSearch([15, 20])).toEqual([15, 18]);
    expect(bst.search(new Range(15, 20, false))).toEqual([18]);
  });

  // Test case for Lowest Common Ancestor (LCA)
  it('@example Find lowest common ancestor', () => {
    const bst = new BST<number>([20, 10, 30, 5, 15, 25, 35, 3, 7, 12, 18]);

    // LCA helper function
    const findLCA = (num1: number, num2: number): number | undefined => {
      const path1 = bst.getPathToRoot(num1);
      const path2 = bst.getPathToRoot(num2);
      // Find the first common ancestor
      return findFirstCommon(path1, path2);
    };

    function findFirstCommon(arr1: number[], arr2: number[]): number | undefined {
      for (const num of arr1) {
        if (arr2.indexOf(num) !== -1) {
          return num;
        }
      }
      return undefined;
    }

    // Assertions
    expect(findLCA(3, 10)).toBe(7);
    expect(findLCA(5, 35)).toBe(15);
    expect(findLCA(20, 30)).toBe(25);
  });
});
