// 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 fileLineIteratorType = "fileLineIterator"

type fileFileLineIterator struct {
	fileIterBase
	line string
}

func newFileLineIterator(r *file.Reader, autoClose bool) *fileFileLineIterator {
	return &fileFileLineIterator{
		fileIterBase: fileIterBase{reader: r, index: -1, count: 0, autoClose: autoClose},
		line:         "",
	}
}

func (it *fileFileLineIterator) TypeName() string {
	return fileLineIteratorType
}

func (it *fileFileLineIterator) String() string {
	return it.repr(fileLineIteratorType)
}

func (it *fileFileLineIterator) Next() (item any, err error) { // must return io.EOF after the last item
	if it.line, err = it.reader.ReadString('\n'); err == nil {
		it.increment()
		item = it.line[0 : len(it.line)-1]
	} else if it.autoClose {
		it.Clean()
	}
	return
}

func (it *fileFileLineIterator) Current() (item any, err error) {
	if len(it.line) > 0 {
		item = it.line[0 : len(it.line)-1]
	}
	return
}

func (it *fileFileLineIterator) Reset() (err error) {
	if err = it.reader.Reset(); err == nil {
		it.reset()
		it.line = ""
	}
	return
}

func (it *fileFileLineIterator) Clean() (err error) {
	if it.reader != nil {
		if err = it.reader.Close(); err == nil {
			it.reader = nil
		}
	}
	// it.reset()
	// it.line = ""
	return
}

func (it *fileFileLineIterator) 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 fileLineIteratorFunc(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 = newFileLineIterator(handle, autoClose)
		}
	}

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