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

// t_builtin-iterator.go
package expr

import (
	"fmt"
	"io"
	"os"
	"testing"

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

const (
	testFilePath = "/tmp/.go-test.txt"
)

func TestFuncRun(t *testing.T) {
	section := "Builtin-Iterator"

	inputs := []inputType{
		/*   1 */ {`builtin "iterator"; it=$(1,2,3); run(it)`, int64(3), nil},
		/*   2 */ {`builtin "iterator"; run($(1,2,3), func(index,item){item+10})`, nil, nil},
		/*   3 */ {`builtin "iterator"; run($(..4), func(index,item){status=status+item; true}, {"status":0})`, int64(6), nil},
		/*   4 */ {`builtin ["iterator", "fmt"]; run($(1,2,3), func(index,item){println(item+10)})`, nil, nil},
		/*   5 */ {`builtin "iterator"; run(nil)`, nil, `type of "iterator" must be iterator, passed <nil> [nil]`},
		/*   6 */ {`builtin "iterator"; run($(1,2,3), nil)`, int64(3), nil},
		/*   7 */ {`builtin "iterator"; run($(1,2,3), func(){1}, "prrr")`, nil, `type of "vars" must be dict, passed prrr [string]`},
		/*   8 */ {`builtin "iterator"; run($(1,2,3), operator=nil)`, int64(3), nil},
		/*   9 */ {`builtin "iterator"; run($(1,2,3), operatorx=nil)`, nil, `run(): unknown param "operatorx"`},
		/*  10 */ {`builtin "iterator"; op = func(index, item){ (index > 2) ? {abort("aborted")} :: {status="ok"} }; run($(..5), op)`, "aborted", nil},
		/*  11 */ {`builtin "iterator"; op = func(index, item){ (index > 2) ? {abort("aborted")} :: {status="ok"} }; run($(..1), op)`, "ok", nil},
	}
	//t.Setenv("EXPR_PATH", ".")

	// RunTestSuiteSpec(t, section, inputs, 10)
	RunTestSuite(t, section, inputs)

	cleanupBuiltinIterator()
}

func TestFuncOsLineIter(t *testing.T) {
	section := "Builtin-OS-File-Line-Iter"
	inputs := []inputType{
		/*  1 */ {fmt.Sprintf(`builtin ["os.file", "iterator"]; it = fileLineIterator(%q); run(it)`, testFilePath), int64(2), nil},
		/*  2 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); it++`, testFilePath), "uno", nil},
		/*  3 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); it++;it++;it++`, testFilePath), nil, io.EOF.Error()},
		/*  4 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); it.clean`, testFilePath), nil, nil},
		/*  5 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); string(it)`, testFilePath),
			fmt.Sprintf(`$(fileLineIterator@%q)`, testFilePath), nil},
		/*  6 */ {fmt.Sprintf(`builtin "os.file"; #$$(fileLineIterator(%q) filter (#${_} == 2))`, testFilePath), int64(0), nil},
		/*  7 */ {fmt.Sprintf(`builtin "os.file"; #$$(fileLineIterator(%q) filter (#${_} == 3))`, testFilePath), int64(2), nil},
		/*  8 */ {fmt.Sprintf(`builtin "os.file"; $$(fileLineIterator(%q) map ${__})`, testFilePath), list.NewLinkedListA(0, 1), nil},
	}

	if err := setupBuiltinIterator(); err != nil {
		t.Error(err)
		return
	}

	// RunTestSuiteSpec(t, section, inputs, 1)
	RunTestSuite(t, section, inputs)

	cleanupBuiltinIterator()
}

func TestFuncOsByteIter(t *testing.T) {
	section := "Builtin-OS-File-Byte-Iter"
	inputs := []inputType{
		/*   1 */ {fmt.Sprintf(`builtin "os.file"; it=fileByteIterator(%q); string(it)`, testFilePath),
			fmt.Sprintf(`$(fileByteIterator@%q)`, testFilePath), nil},
		/*   2 */ {fmt.Sprintf(`builtin ["os.file", "string"]; it=fileByteIterator(%q); char(it++)`, testFilePath), `u`, nil},
		/*   3 */ {fmt.Sprintf(`builtin ["os.file", "string"]; it=fileByteIterator(%q); it++; it.reset; char(it++)`, testFilePath), `u`, nil},
	}

	if err := setupBuiltinIterator(); err != nil {
		t.Error(err)
		return
	}

	// t.Setenv("EXPR_PATH", ".")

	// RunTestSuiteSpec(t, section, inputs, 24)
	RunTestSuite(t, section, inputs)

	cleanupBuiltinIterator()
}

func setupBuiltinIterator() (err error) {
	var fh *os.File
	// Create test file
	if fh, err = os.Create(testFilePath); err == nil {
		defer fh.Close()
		fmt.Fprintln(fh, "uno")
		fmt.Fprintln(fh, "due")
	}
	return
}

func cleanupBuiltinIterator() {
	if fileExists(testFilePath) {
		os.Remove(testFilePath)
	}
}
