diff --git a/__main__.py b/__main__.py
index b542589fb4f6b0342676d431cef25d9620645a3b..ab4fb51efed46d345af8780f9b12d2913ff2a50b 100644
--- a/__main__.py
+++ b/__main__.py
@@ -69,18 +69,6 @@ class Node:
         self.children = []
 
 
-def find_leaf(root, key):
-    parents = []
-    current = root
-
-    while not current.is_leaf:
-        parents.append(current)
-        children_index = lower_bound(current.keys, key)
-        current = current.children[children_index]
-
-    return parents, current
-
-
 def node_is_full(node):
     return len(node.keys) == 2 * node.order
 
@@ -191,8 +179,20 @@ def insert_non_full(node, key, previous_split_right_node):
         node.children.insert(inserted_at_index + 1, previous_split_right_node)
 
 
+def insertion_find_leaf(root, key):
+    parents = []
+    current = root
+
+    while not current.is_leaf:
+        parents.append(current)
+        children_index = lower_bound(current.keys, key)
+        current = current.children[children_index]
+
+    return parents, current
+
+
 def bptree_insert(root, key):
-    parents, leaf = find_leaf(root, key)
+    parents, leaf = insertion_find_leaf(root, key)
 
     if node_is_full(leaf):
         insert_full(root, parents, leaf, key, None)
@@ -205,15 +205,80 @@ def bptree_insert(root, key):
 # DELETION : START
 
 
-def bptree_delete(root, key):
-    parents, leaf = find_leaf(root, key)
+def deletion_find_leaf(root, key):
+    parents = []
+    current = root
+
+    while not current.is_leaf:
+        parents.append(current)
+        children_index = lower_bound(current.keys, key)
+
+        if children_index < len(current.keys) and current.keys[children_index] == key:
+            children_index += 1
+
+        current = current.children[children_index]
+
+    return parents, current
 
-    if not is_value_in_array(leaf.keys, key):
-        return
 
+def bptree_find_smallest_key(root):
+    if root.is_leaf:
+        return root.keys[0]
+
+    return bptree_find_smallest_key(root.children[0])
+
+
+def bptree_shrink(root):
+    right_child = root.children[1]
+    root.keys = right_child.keys
+    root.children = right_child.children
+
+
+def bptree_delete_internal(root, parents, node, key):
+    if node != root:
+        parent = parents.pop()
+
+    if len(node.keys) < node.order and node != root:
+        children_index = None
+
+        for i, child in enumerate(parent.children):
+            if node == child:
+                children_index = i
+
+        if children_index == 0:
+            sibling = parent.children[children_index + 1]
+            parent_key = parent.keys[children_index]
+            parent.keys.pop(find_value_index_in_array(parent.keys, parent_key))
+            array_insert_sorted(sibling.keys, parent_key)
+            array_insert_sorted(sibling.keys, node.keys[0])
+            sibling.children = node.children + sibling.children
+        else:
+            sibling = parent.children[children_index - 1]
+            parent_key = parent.keys[children_index - 1]
+            parent.keys.pop(find_value_index_in_array(parent.keys, parent_key))
+            array_insert_sorted(node.keys, parent_key)
+
+            for key in sibling.keys:
+                array_insert_sorted(node.keys, key)
+
+            node.children = sibling.children + node.children
+
+        if parent == root and len(parent.keys) == 0:
+            bptree_shrink(root)
+
+    if is_value_in_array(node.keys, key):
+        index = find_value_index_in_array(node.keys, key)
+        node.keys[index] = bptree_find_smallest_key(node.children[index + 1])
+
+    if node != root:
+        bptree_delete_internal(root, parents, parent, key)
+
+
+def bptree_delete_leaf(root, parents, leaf, key):
     if len(leaf.keys) > leaf.order:
         deletion_index = find_value_index_in_array(leaf.keys, key)
         leaf.keys.pop(deletion_index)
+        bptree_delete_internal(root, parents, parents.pop(), key)
     else:
         deletion_index = find_value_index_in_array(leaf.keys, key)
         leaf.keys.pop(deletion_index)
@@ -226,24 +291,72 @@ def bptree_delete(root, key):
                 children_index = i
 
         if children_index == 0:
-            sibling = parent.children[children_index + 1]
-        else:
+            # Must take the sibling on the right.
+            sibling = parent.children[1]
+            sibling_position = "r"
+        elif children_index == 2 * leaf.order - 1:
+            # Must take the sibling on the left.
             sibling = parent.children[children_index - 1]
-
-        if len(sibling.keys) == leaf.order:
-            pass
+            sibling_position = "l"
         else:
-            # Works only if children_index = 0
-            borrowed_key = sibling.keys[0]
-            sibling.keys.pop(0)
-            leaf.keys.append(borrowed_key)
-            parent.keys[0] = sibling.keys[0]
+            # Can take the sibling from left or right.
+            if len(parent.children[children_index - 1].keys) > leaf.order:
+                # The left sibling has enough keys to borrow one.
+                sibling = parent.children[children_index - 1]
+                sibling_position = "l"
+            elif len(parent.children[children_index + 1].keys) > leaf.order:
+                # The right sibling has enough keys to borrow one.
+                sibling = parent.children[children_index + 1]
+                sibling_position = "r"
+            else:
+                # A merge between the node and the left sibling is required.
+                sibling = parent.children[children_index - 1]
+
+        if len(sibling.keys) == sibling.order:
+            if children_index == 0:
+                # Sibling not on the left.
+                array_insert_sorted(sibling.keys, leaf.keys[0])
+                parent.children.pop(children_index)
+                parent.keys.pop(children_index)
+            else:
+                for key in sibling.keys:
+                    array_insert_sorted(leaf.keys, key)
+
+                parent.children.pop(children_index - 1)
+                parent.keys.pop(children_index - 1)
+
+            bptree_delete_internal(root, parents, parent, key)
+        else:
+            if sibling_position == "l":
+                sibling_key = sibling.keys[len(sibling.keys) - 1]
+                deletion_index = find_value_index_in_array(sibling.keys, sibling_key)
+                sibling.keys.pop(deletion_index)
+                array_insert_sorted(leaf.keys, sibling_key)
+                parent.keys[children_index - 1] = sibling_key
+            else:
+                sibling_key = sibling.keys[0]
+                deletion_index = find_value_index_in_array(sibling.keys, sibling_key)
+                sibling.keys.pop(deletion_index)
+                array_insert_sorted(leaf.keys, sibling_key)
+                parent.keys[children_index] = sibling.keys[0]
+
+            bptree_delete_internal(root, parents, parent, key)
+
+
+def bptree_delete(root, key):
+    parents, leaf = deletion_find_leaf(root, key)
+
+    if not is_value_in_array(leaf.keys, key):
+        return
+
+    bptree_delete_leaf(root, parents, leaf, key)
 
 
 # DELETION : END
 
 
 def bptree_search(root, key):
+    # BUG !!!
     if root.is_leaf:
         return is_value_in_array(root.keys, key)
 
@@ -300,7 +413,8 @@ def generate_random_keys(length, min_key, max_key):
 
 
 def main():
-    random.seed(0)
+    a = 2
+    random.seed(a)
 
     order = 2
     # root = Node(order)
@@ -327,16 +441,23 @@ def main():
     #     assert not bptree_search(root, random_key)
 
     root = Node(order)
-    keys = generate_random_keys(8, 1, 99)
+    keys = generate_random_keys(18, 1, 99)
     print(keys)
     print("=====")
 
     for key in keys:
         bptree_insert(root, key)
 
-    bptree_delete(root, 51)
-    # bptree_delete(root, 52)
-    bptree_delete(root, 34)
+    bptree_delete(root, 56)
+    bptree_delete(root, 82)
+    bptree_delete(root, 75)
+    bptree_insert(root, 80)
+    bptree_delete(root, 47)
+    # bptree_delete(root, 80)
+    bptree_delete(root, 21)
+    bptree_delete(root, 22)
+    bptree_delete(root, 12)
+    bptree_delete(root, 8)
     bptree_print(root)