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

// list-iterator.go
package expr

import (
	"fmt"
	"io"
	"slices"

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

type LinkedListIterator struct {
	a       *list.LinkedList
	count   int64
	index   int64
	current *list.ListNode
}

func NewLinkedListIterator(list *list.LinkedList, args []any) (it *LinkedListIterator) {
	it = &LinkedListIterator{a: list, count: 0, index: -1, current: list.FirstNode()}
	return
}

func (it *LinkedListIterator) String() string {
	var l = int64(0)
	if it.a != nil {
		l = int64(it.a.Len())
	}
	return fmt.Sprintf("$([<#%d>])", l)
}

func (it *LinkedListIterator) TypeName() string {
	return "LinkedListIterator"
}

func (it *LinkedListIterator) HasOperation(name string) bool {
	yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name)
	return yes
}

func (it *LinkedListIterator) CallOperation(name string, args map[string]any) (v any, err error) {
	switch name {
	case kern.NextName:
		v, err = it.Next()
	case kern.ResetName:
		err = it.Reset()
	case kern.CleanName:
		err = it.Clean()
	case kern.IndexName:
		v = int64(it.Index())
	case kern.CurrentName:
		v, err = it.Current()
	case kern.CountName:
		v = it.count
	default:
		err = kern.ErrNoOperation(name)
	}
	return
}

func (it *LinkedListIterator) Current() (item any, err error) {
	if it.current != nil {
		item = it.current.Data()
	} else {
		err = io.EOF
	}
	return
}

func (it *LinkedListIterator) Next() (item any, err error) {
	if it.current != nil {
		item = it.current.Data()
		it.current = it.current.Next()
		it.index++
		it.count++
	} else {
		err = io.EOF
	}
	return
}

func (it *LinkedListIterator) Index() int64 {
	return it.index
}

func (it *LinkedListIterator) Count() int64 {
	return it.count
}

func (it *LinkedListIterator) Reset() error {
	it.current = it.a.FirstNode()
	it.index = -1
	it.count = 0
	return nil
}

func (it *LinkedListIterator) Clean() error {
	return nil
}
