text: const { NotImplementedError } = require("../extensions/index.js");
  
  const { Node } = require("../extensions/list-tree.js");
  
  /**
   * Implement simple binary search tree according to task description
   * using Node from extensions
   */
  
  module.exports = class BinarySearchTree {
    constructor() {
      this._root = null;
    }
  
    root() {
      return !this._root ? null : this._root;
    }
  
    add(data) {
      this._root = addNode(this._root, data);
  
      function addNode(node, data) {
        if (!node) return new Node(data);
  
        if (node.value === data) return node;
  
        if (data < node.data) {
          node.left = addNode(node.left, data);
        } else {
          node.right = addNode(node.right, data);
        }
        return node;
      }
    }
  
    has(data) {
      return ifNodeExists(this._root, data);
  
      function ifNodeExists(node, data) {
        if (!node) return false;
  
        if (node.data === data) return true;
  
        return data < node.data
          ? ifNodeExists(node.left, data)
          : ifNodeExists(node.right, data);
      }
    }
  
    find(data) {
      return findNode(this._root, data);
  
      function findNode(node, data) {
        if (!node) return null;
  
        if (node.data === data) return node;
  
        return data < node.data
          ? findNode(node.left, data)
          : findNode(node.right, data);
      }
    }
  
    remove(data) {
      this._root = deleteNode(this._root, data);
  
      function deleteNode(node, data) {
        if (!node) return null;
  
        if (data < node.data) {
          node.left = deleteNode(node.left, data);
          return node;
        } else if (data > node.data) {
          node.right = deleteNode(node.right, data);
          return node;
        } else {
          if (!node.left && !node.right) return null;
  
          if (!node.left) {
            node = node.right;
            return node;
          }
  
          if (!node.right) {
            node = node.left;
            return node;
          }
  
          let minInRight = node.right;
          while (minInRight.left) {
            minInRight = minInRight.left;
          }
  
          node.data = minInRight.data;
          node.right = deleteNode(node.right, minInRight.data);
          return node;
        }
      }
    }
  
    min() {
      if (!this._root) return;
  
      let minNode = this._root;
      while (minNode.left) {
        minNode = minNode.left;
      }
      return minNode.data;
    }
  
    max() {
      if (!this._root) return;
  
      let maxNode = this._root;
      while (maxNode.right) {
        maxNode = maxNode.right;
      }
      return maxNode.data;
    }
  };
  