package linked_list

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

/*
Связный список (LinkedListPhoneBook)

Узел представляется словарём: `{'name': 'Имя', 'phone': '123', 'next': None}.`

Функции:

def ll_insert(head, name, phone) — проходит до конца (или сразу добавляет в конец) и возвращает новую голову (если вставка в начало) или изменяет список по ссылке. Удобнее возвращать новую голову, если вставка может быть в начало.

def ll_find(head, name) — ищет узел, возвращает телефон или None.

def ll_delete(head, name) — удаляет узел, возвращает новую голову.

def ll_list_all(head) — собирает все записи в список и сортирует (сортировка вынесена отдельно).
*/

type LinkedList struct {
	head *LList
}

type LList struct {
	data ds.MyData

	next *LList
}

func NewLinkedList() *LinkedList {
	return &LinkedList{}
}

func newLinkedList(data ds.MyData) *LList {
	return &LList{
		data: data,
		next: nil,
	}
}

func (ll *LList) ToString() string {
	if ll == nil {
		return "nil"
	}
	return ll.data.ToString()
}

func (ll *LinkedList) Len() int {

	if ll == nil {
		return 0
	}
	len := 0

	current := ll.head
	for current != nil {
		len++
		current = current.next
	}

	return len
}

func (ll *LinkedList) Insert(data ds.MyData) {
	newNode := newLinkedList(data)

	if ll.head == nil {
		ll.head = newNode
		return
	}

	current := ll.head
	for current.next != nil {
		current = current.next
	}
	current.next = newNode
}

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

func (ll *LinkedList) Search(targetName string) (string, bool) {
	current := ll.head

	for current != nil {
		if current.data.Name == targetName {
			return current.data.Phone, true
		}

		current = current.next
	}
	return "", false
}

func (ll *LinkedList) PrintAll() {
	current := ll.head
	index := 0

	for current != nil {
		fmt.Printf("[%d] %s\n", index, current.ToString())
		index++
		current = current.next
	}
}

func (ll *LinkedList) Delete(targetName string) bool {
	if ll.head == nil {
		return false
	}

	// Особый случай: удаление головы списка
	if ll.head.data.Name == targetName {
		// Сдвигаем данные и указатель
		*ll.head = *ll.head.next
		return true
	}

	// Стандартное удаление из середины/конца
	current := ll.head
	for current.next != nil {
		if current.next.data.Name == targetName {
			current.next = current.next.next
			return true
		}
		current = current.next
	}

	return false
}

func (ll *LinkedList) listAll() []ds.MyData {
	current := ll.head

	listLL := make([]ds.MyData, ll.Len())
	ind := 0
	for current != nil {
		listLL[ind] = current.data
		ind++
		current = current.next
	}

	listLL = ds.QSort(listLL, 0, len(listLL)-1)
	return listLL
}

func (ll *LinkedList) GetByInd(ind int) (ds.MyData, bool) {
	if ind >= ll.Len() {
		return ds.MyData{}, false
	}

	index := 0
	current := ll.head
	for current != nil {
		if index == ind {
			return current.data, true
		}
		current = current.next
		index++
	}

	return ds.MyData{}, false
}
