package bin_search_tree

import (
	"fmt"
	ds "source/pkg/data_struct"
)

type BinSearchTree struct {
	root *BSTree
}

type BSTree struct {
	data ds.MyData

	left  *BSTree
	right *BSTree
}

func NewBinSearchTree() *BinSearchTree {
	return &BinSearchTree{}
}

func newBinSearchTree(data ds.MyData) *BSTree {
	return &BSTree{
		data:  data,
		left:  nil,
		right: nil,
	}
}

func (bst *BinSearchTree) Len() int {
	return bst.root.Len()
}

func (bst *BSTree) Len() int {
	if bst == nil {
		return 0
	}
	return 1 + bst.left.Len() + bst.right.Len()
}

func (bst *BinSearchTree) Minimum() *BSTree {
	return bst.root.Minimum()
}

func (root *BSTree) Minimum() *BSTree {
	if root == nil {
		return nil
	}
	if root.left == nil {
		return root
	}
	return root.left.Minimum()
}

func (bst *BinSearchTree) Maximum() *BSTree {
	return bst.root.Maximum()
}
func (root *BSTree) Maximum() *BSTree {
	if root == nil {
		return nil
	}
	if root.right == nil {
		return root
	}
	return root.right.Maximum()
}

func (node *BSTree) PrintNode() {
	fmt.Print(node.data.ToString())
}

func (node *BSTree) ToString() string {
	if node == nil {
		return "nil"
	}
	return node.data.ToString()
}

func (bst *BinSearchTree) BstInorderTraversal() {
	bst.root.BstInorderTraversal()
}

func (root *BSTree) BstInorderTraversal() {
	if root != nil {
		root.left.BstInorderTraversal()
		root.PrintNode()
		fmt.Println()
		root.right.BstInorderTraversal()
	}
}

func (bst *BinSearchTree) BstPreorderTraversal() {
	bst.root.BstPreorderTraversal()
}

func (root *BSTree) BstPreorderTraversal() {
	if root != nil {
		root.PrintNode()
		fmt.Println()
		root.left.BstPreorderTraversal()
		root.right.BstPreorderTraversal()
	}
}

// Search
// Возвращает номер телефона по имени
func (bst *BinSearchTree) Search(targetName string) (string, bool) {
	node, ok := bst.root.search(targetName)
	if ok {
		return node.data.Phone, true
	}
	return "", false
}

/*
	Node search(x : Node, k : T):
   if x == null or k == x.key
      return x
   if k < x.key
      return search(x.left, k)
   else
      return search(x.right, k)
*/
// Приватная вспомогательная функция поиска
func (node *BSTree) search(targetName string) (*BSTree, bool) {
	if node == nil {
		return nil, false
	}
	if node.data.Name == targetName {
		return node, true
	}
	if targetName < node.data.Name {
		return node.left.search(targetName)
	}
	return node.right.search(targetName)
}

// func (node *BinSearchTree) Insert(data ds.MyData) *BinSearchTree {
// 	if node == nil {
// 		return NewBinSearchTree(data)
// 	} else if data.Name < node.data.Name {
// 		node.left = node.left.Insert(data)
// 	} else if data.Name > node.data.Name {
// 		node.right = node.right.Insert(data)
// 	} else {
// 		node.data.Phone = data.Phone // Заменяем существующее значение
// 	}
// 	return node
// }

func (bst *BinSearchTree) Insert(data ds.MyData) {
	bst.root = bst.root.insert(data)
}

func (root *BSTree) insert(data ds.MyData) *BSTree {
	if root == nil {
		return &BSTree{
			data: data,
		}
	}

	if data.Name < root.data.Name {
		root.left = root.left.insert(data)
	} else if data.Name > root.data.Name {
		root.right = root.right.insert(data)
	} else {
		root.data.Phone = data.Phone
	}
	return root
}

func (bst *BinSearchTree) InsertAll(data []ds.MyData) {
	for _, el := range data {
		bst.Insert(el)
	}
}

// Delete удаляет узел по имени.
// Возвращает нового потомка для родительского узла.

/*
Node delete(root : Node, z : T):               // корень поддерева, удаляемый ключ
  if root == null
    return root
  if z < root.key
    root.left = delete(root.left, z)
  else if z > root.key
    root.right = delete(root.right, z)
  else if root.left != null and root.right != null
    root.key = minimum(root.right).key
    root.right = delete(root.right, root.key)
  else
    if root.left != null
      root = root.left
    else if root.right != null
      root = root.right
    else
      root = null
  return root
*/

func (bst *BinSearchTree) Height() int {
	if bst.root == nil {
		return 0
	}
	return bst.root.height()
}

// height возвращает высоту поддерева (для BSTree)
func (node *BSTree) height() int {
	if node == nil {
		return 0
	}

	leftHeight := node.left.height()
	rightHeight := node.right.height()

	// Высота = 1 (текущий узел) + максимум из высот поддеревьев
	if leftHeight > rightHeight {
		return leftHeight + 1
	}
	return rightHeight + 1
}

func (bst *BinSearchTree) Delete(targetName string) bool {
	if bst.root == nil {
		return false
	}

	_, found := bst.Search(targetName)
	if !found {
		return false
	}

	bst.root = bst.root.delete(targetName)
	return true
}

func (root *BSTree) delete(targetName string) *BSTree {
	if root == nil {
		return nil
	}

	if targetName < root.data.Name {
		root.left = root.left.delete(targetName)
	} else if targetName > root.data.Name {
		root.right = root.right.delete(targetName)
	} else {
		// Нашли узел для удаления

		// Случай 1: нет левого потомка
		if root.left == nil {
			return root.right
		}

		// Случай 2: нет правого потомка
		if root.right == nil {
			return root.left
		}

		// Случай 3: оба потомка есть
		successor := root.right.Minimum()
		root.data = successor.data // Копируем все данные сразу
		root.right = root.right.delete(successor.data.Name)
	}

	return root
}

func (bst *BinSearchTree) PrintAll() {
	bst.root.printAll(0)
}

func (bst *BSTree) printAll(depth int) {
	if bst == nil {
		return
	}

	bst.right.printAll(depth + 1)

	for i := 0; i < depth; i++ {
		fmt.Printf("\t")
	}
	bst.PrintNode()
	bst.left.printAll(depth + 1)
}
