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

// builtin-os-file.go
package expr

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

const fileByteIteratorType = "fileByteIterator"

type fileFileByteIterator struct {
	fileIterBase
	b byte
}

func newFileByteIterator(r *file.Reader, autoClose bool) *fileFileByteIterator {
	return &fileFileByteIterator{
		fileIterBase: fileIterBase{reader: r, index: -1, count: 0, autoClose: autoClose},
		b:            0}
}

func (it *fileFileByteIterator) TypeName() string {
	return fileByteIteratorType
}

func (it *fileFileByteIterator) String() string {
	return it.repr(fileByteIteratorType)
}

func (it *fileFileByteIterator) Next() (item any, err error) { // must return io.EOF after the last item
	if it.b, err = it.reader.ReadByte(); err == nil {
		it.increment()
		item = it.b
	} else if it.autoClose {
		it.Clean()
	}
	return
}

func (it *fileFileByteIterator) Current() (item any, err error) {
	item = it.b
	return
}

func (it *fileFileByteIterator) Reset() (err error) {
	if err = it.reader.Reset(); err == nil {
		it.reset()
		it.b = 0
	}
	return
}

func (it *fileFileByteIterator) Clean() (err error) {
	if it.reader.Valid() {
		if err = it.reader.GetFile().Close(); err == nil {
			it.reader = nil
		}
	}
	// it.reset()
	// it.b = 0
	return
}

func (it *fileFileByteIterator) 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 fileByteIteratorFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
	var handle *file.Reader
	var invalidFileHandle any
	var autoClose bool

	if handle, invalidFileHandle, autoClose, err = initFileHandle(ctx, name, args); err == nil {
		if handle != nil {
			result = newFileByteIterator(handle, autoClose)
		}
	}

	if err == nil && (handle == nil || invalidFileHandle != nil) {
		err = errInvalidFileHandle(name, invalidFileHandle)
	}
	return
}
