// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// linked-list-type.go
package list

import (
	"strings"

	"git.portale-stac.it/go-pkg/expr/kern"
)

const LinkedListTypeName = "lisked-list"

func IsLinkedList(v any) (ok bool) {
	_, ok = v.(*LinkedList)
	return ok
}

func NewLinkedListA(listAny ...any) (list *LinkedList) {
	if listAny == nil {
		listAny = []any{}
	}
	list = NewLinkedList()
	for _, item := range listAny {
		list.PushBack(kern.FixAnyNumber(item))
	}
	return
}

func LinkedListFromStrings(stringList []string) (list *LinkedList) {
	list = NewLinkedList()
	for _, s := range stringList {
		list.PushBack(s)
	}
	return
}

func (ls *LinkedList) ToString(opt kern.FmtOpt) (s string) {
	indent := kern.GetFormatIndent(opt)
	flags := kern.GetFormatFlags(opt)

	var sb strings.Builder
	sb.WriteString("[<")
	if ls.Len() > 0 {
		innerOpt := kern.MakeFormatOptions(flags, indent+1)
		nest := strings.Repeat("  ", indent+1)

		if flags&kern.MultiLine != 0 {
			sb.WriteByte('\n')
			sb.WriteString(nest)
		}

		i := 0
		for item := ls.FirstNode(); item != nil; item = item.Next() {
			if i > 0 {
				if flags&kern.MultiLine != 0 {
					sb.WriteString(",\n")
					sb.WriteString(nest)
				} else {
					sb.WriteString(", ")
				}
			}

			kern.Format(&sb, item.Data(), innerOpt)
			i++
		}
		if flags&kern.MultiLine != 0 {
			sb.WriteByte('\n')
			sb.WriteString(strings.Repeat("  ", indent))
		}
	}
	sb.WriteString(">]")
	s = sb.String()
	if flags&kern.Truncate != 0 && len(s) > kern.TruncateSize {
		s = kern.TruncateString(s)
	}
	return
}

func (ls *LinkedList) String() string {
	return ls.ToString(0)
}

func (ls *LinkedList) TypeName() string {
	return LinkedListTypeName
}

// func (ls *LinkedList) Contains(t *ListType) (answer bool) {
// 	if len(*ls) >= len(*t) {
// 		answer = true
// 		for _, item := range *t {
// 			if answer = ls.IndexDeepSameCmp(item) >= 0; !answer {
// 				break
// 			}
// 		}
// 	}
// 	return
// }

func (ls1 *LinkedList) EqualTo(other kern.Equaler) (answer bool) {
	if ls2, ok := other.(*LinkedList); ok {
		answer = ls1.Equals(ls2)
	}
	return
}

func (ls1 *LinkedList) Equals(ls2 *LinkedList) (answer bool) {
	if ls2 != nil && ls1.Len() == ls2.Len() {
		answer = true
		i2 := ls2.FirstNode()
		for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() {
			if !kern.Equal(i1.Data(), i2.Data()) {
				answer = false
				break
			}
			i2 = i2.Next()
		}
	}
	return
}

func (ls1 *LinkedList) Clone() (ls2 *LinkedList) {
	ls2 = NewLinkedListA()
	for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() {
		ls2.PushBack(kern.Clone(i1.Data()))
	}
	return
}

func (ls *LinkedList) HasValue(value any) (found bool) {
	for node := ls.FirstNode(); node != nil; node = node.Next() {
		if kern.Equal(node.Data(), value) {
			found = true
			break
		}
	}
	return
}

func (ls *LinkedList) Index(value any) (index int64) {
	index = -1
	i := int64(0)
	for node := ls.FirstNode(); node != nil; node = node.Next() {
		if kern.Equal(node.Data(), value) {
			index = i
			break
		}
		i++
	}
	return
}
