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

// list_test.go
package expr

import (
	"errors"
	"strings"
	"testing"
)

func TestListParser(t *testing.T) {
	section := "List"

	type inputType struct {
		source     string
		wantResult any
		wantErr    error
	}

	inputs := []inputType{
		/*   1 */ {`[]`, []any{}, nil},
		/*   2 */ {`[1,2,3]`, []any{int64(1), int64(2), int64(3)}, nil},
		/*   3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil},
		/*   4 */ {`[1+2, not true, "hello"]`, []any{int64(3), false, "hello"}, nil},
		/*   5 */ {`[1,2]+[3]`, []any{int64(1), int64(2), int64(3)}, nil},
		/*   6 */ {`[1,4,3,2]-[3]`, []any{int64(1), int64(4), int64(2)}, nil},
		/*   7 */ {`add([1,4,3,2])`, int64(10), nil},
		/*   8 */ {`add([1,[2,2],3,2])`, int64(10), nil},
		/*   9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil},
		/*  10 */ {`add([1,"hello"])`, nil, errors.New(`add(): param nr 2 (2 in 1) has wrong type string, number expected`)},
		/*  11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
		/*  12 */ {`[1,2,3] << 2+2`, []any{int64(1), int64(2), int64(3), int64(4)}, nil},
		/*  13 */ {`2-1 >> [2,3]`, []any{int64(1), int64(2), int64(3)}, nil},
		/*  14 */ {`[1,2,3].1`, int64(2), nil},
		/*  15 */ {`ls=[1,2,3] but ls.1`, int64(2), nil},
		/*  16 */ {`ls=[1,2,3] but ls.(-1)`, int64(3), nil},
		/*  17 */ {`list=["one","two","three"]; list.10`, nil, errors.New(`[1:36] index 10 out of bounds`)},
		/*  18 */ {`["a", "b", "c"]`, newListA("a", "b", "c"), nil},
		/*  19 */ {`["a", "b", "c"]`, newList([]any{"a", "b", "c"}), nil},
		/*  20 */ {`#["a", "b", "c"]`, int64(3), nil},

		// /*  8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil},
		// /*  9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil},
	}

	succeeded := 0
	failed := 0

	// inputs1 := []inputType{
	// 	/*  7 */ {`add([1,4,3,2])`, int64(10), nil},
	// }

	for i, input := range inputs {
		var expr *ast
		var gotResult any
		var gotErr error

		ctx := NewSimpleFuncStore()
		ctx.SetVar("var1", int64(123))
		ctx.SetVar("var2", "abc")
		ImportMathFuncs(ctx)
		parser := NewParser(ctx)

		logTest(t, i+1, "List", input.source, input.wantResult, input.wantErr)

		r := strings.NewReader(input.source)
		scanner := NewScanner(r, DefaultTranslations())

		good := true
		if expr, gotErr = parser.Parse(scanner); gotErr == nil {
			gotResult, gotErr = expr.Eval(ctx)
		}

		if (gotResult == nil && input.wantResult != nil) || (gotResult != nil && input.wantResult == nil) {
			t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult)
			good = false
		}

		if gotList, okGot := gotResult.([]any); okGot {
			if wantList, okWant := input.wantResult.([]any); okWant {
				if (gotList == nil && wantList != nil) || (gotList != nil && wantList == nil) {
					t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult)
					good = false
				} else {
					equal := len(gotList) == len(wantList)
					if equal {
						for i, gotItem := range gotList {
							wantItem := wantList[i]
							equal = gotItem == wantItem
							if !equal {
								break
							}
						}
					}
					if !equal {
						t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult)
						good = false
					}
				}
			}
		}

		if gotErr != input.wantErr {
			if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) {
				t.Errorf("%d: %q  -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr)
				good = false
			}
		}

		if good {
			succeeded++
		} else {
			failed++
		}
	}
	t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed)
}