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

// t_dict_test.go
package expr

import (
	"errors"

	"strings"
	"testing"
)

func TestDictParser(t *testing.T) {
	section := "Dict"

	type inputType struct {
		source     string
		wantResult any
		wantErr    error
	}

	inputs := []inputType{
		/*  1 */ {`{}`, map[any]any{}, nil},
		/*  2 */ {`{123}`, nil, errors.New(`[1:6] expected ":", got "}"`)},
		/*  3 */ {`{1:"one",2:"two",3:"three"}`, map[int64]any{int64(1): "one", int64(2): "two", int64(3): "three"}, nil},
		/*  4 */ {`{1:"one",2:"two",3:"three"}[3]`, "three", nil},
		/*  5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
		/*  6 */ {`{1:"one"} + {2:"two"}`, map[any]any{1: "one", 2: "two"}, nil},
		/*  7 */ {`2 in {1:"one", 2:"two"}`, true, nil},
		/*  8 */ {`D={"a":1, "b":2}; D["a"]=9; D`, map[any]any{"a": 9, "b": 2}, nil},
		/*  9 */ {`D={"a":1, "b":2}; D["z"]=9; D`, map[any]any{"z": 9, "a": 1, "b": 2}, nil},
		/* 10 */ {`D={"a":1, "b":2}; D[nil]=9`, nil, errors.New(`[1:21] index/key is nil`)},
		/* 11 */ {`D={"a":1, "b":2}; D["a"]`, int64(1), 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 := NewSimpleStore()
		ctx.SetVar("var1", int64(123))
		ctx.SetVar("var2", "abc")
		ImportMathFuncs(ctx)
		parser := NewParser()

		logTest(t, i+1, "Dict", 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)
}

func TestDictToStringMultiLine(t *testing.T) {
	var good bool
	section := "dict-ToString-ML"
	want := `{
  "first": 1
}`
	args := map[any]*term{
		"first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)),
	}
	dict := newDict(args)
	got := dict.ToString(MultiLine)
	// fmt.Printf("got=%q\n", got)

	if good = got == want; !good {
		t.Errorf("ToString(MultiLine): got = %q, want %q", got, want)
	}

	if good {
		t.Logf("%s -- succeeded", section)
	} else {
		t.Logf("%s -- failed", section)
	}
}

func TestDictToString(t *testing.T) {
	var good bool
	section := "dict-ToString-SL"
	want := `{"first": 1}`
	args := map[any]*term{
		"first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)),
	}
	dict := newDict(args)
	got := dict.ToString(0)
	// fmt.Printf("got=%q\n", got)

	if good = got == want; !good {
		t.Errorf("ToString(0): got = %q, want %q", got, want)
	}

	if good {
		t.Logf("%s -- succeeded", section)
	} else {
		t.Logf("%s -- failed", section)
	}
}
