internal BSTNode(BSTNode <T> parent, T value)
 {
     Parent = parent;
     Value  = value;
 }
        //worst O(n) for unbalanced tree
        private BSTNode <T> delete(BSTNode <T> node, T value)
        {
            while (true)
            {
                if (node != null)
                {
                    var compareResult = node.Value.CompareTo(value);

                    //node is less than the search value so move right to find the deletion node
                    if (compareResult < 0)
                    {
                        node = node.Right ?? throw new Exception("Item do not exist");
                        continue;
                    }

                    //node is less than the search value so move left to find the deletion node
                    if (compareResult > 0)
                    {
                        node = node.Left ?? throw new Exception("Item do not exist");
                        continue;
                    }
                }

                if (node == null)
                {
                    return(null);
                }


                //node is a leaf node
                if (node.IsLeaf)
                {
                    deleteLeaf(node);
                    return(node);
                }

                //case one - right tree is null (move sub tree up)
                if (node.Left != null && node.Right == null)
                {
                    deleteLeftNode(node);
                    return(node);
                }

                //case two - left tree is null  (move sub tree up)
                if (node.Right != null && node.Left == null)
                {
                    deleteRightNode(node);
                    return(node);
                }

                //case three - two child trees
                //replace the node value with maximum element of left subtree (left max node)
                //and then delete the left max node
                var maxLeftNode = FindMax(node.Left);

                node.Value = maxLeftNode.Value;

                //delete left max node
                node  = node.Left;
                value = maxLeftNode.Value;
            }
        }