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

// t_scanner_test.go
package scan

import (
	"errors"
	"reflect"
	"strings"
	"testing"

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

func TestScanner(t *testing.T) {
	type inputType struct {
		source    string
		wantSym   sym.Symbol
		wantValue any
		wantErr   error
	}

	inputs := []inputType{
		/*  1 */ {`123`, sym.SymInteger, int64(123), nil},
		/*  2 */ {"=", sym.SymEqual, nil, nil},
		/*  3 */ {`--`, sym.SymDoubleMinus, nil, nil},
		/*  4 */ {`++`, sym.SymDoublePlus, nil, nil},
		/*  5 */ {`**`, sym.SymDoubleStar, nil, nil},
		/*  6 */ {`&&`, sym.SymDoubleAmpersand, nil, nil},
		/*  7 */ {`||`, sym.SymDoubleVertBar, nil, nil},
		/*  8 */ {`NOT`, sym.SymKwNot, nil, nil},
		/*  9 */ {`AND`, sym.SymKwAnd, nil, nil},
		/* 10 */ {`or`, sym.SymKwOr, nil, nil},
		/* 11 */ {`+=`, sym.SymPlusEqual, nil, nil},
		/* 12 */ {`-=`, sym.SymMinusEqual, nil, nil},
		/* 13 */ {`|`, sym.SymVertBar, nil, nil},
		/* 14 */ {`:`, sym.SymColon, nil, nil},
		/* 15 */ {`;`, sym.SymSemiColon, nil, nil},
		/* 16 */ {`.`, sym.SymDot, nil, nil},
		/* 17 */ {`0.5`, sym.SymFloat, float64(0.5), nil},
		/* 18 */ {`\\`, sym.SymBackSlash, nil, nil},
		/* 19 */ {"`", sym.SymBackTick, nil, nil},
		/* 20 */ {"?", sym.SymQuestion, nil, nil},
		/* 21 */ {"&", sym.SymAmpersand, nil, nil},
		/* 22 */ {"@", sym.SymAt, nil, nil},
		/* 23 */ {`#`, sym.SymHash, nil, nil},
		/* 24 */ {`%`, sym.SymPercent, nil, nil},
		/* 25 */ {`\'`, sym.SymQuote, nil, nil},
		/* 26 */ {`\"`, sym.SymDoubleQuote, nil, nil},
		/* 27 */ {`_`, sym.SymUndescore, nil, nil},
		/* 28 */ {`<>`, sym.SymLessGreater, nil, nil},
		/* 29 */ {`[`, sym.SymOpenSquare, nil, nil},
		/* 30 */ {`]`, sym.SymClosedSquare, nil, nil},
		/* 31 */ {`{`, sym.SymOpenBrace, nil, nil},
		/* 32 */ {`}`, sym.SymClosedBrace, nil, nil},
		/* 33 */ {`(`, sym.SymOpenRound, nil, nil},
		/* 34 */ {`)`, sym.SymClosedRound, nil, nil},
		/* 35 */ {`1E+2`, sym.SymFloat, float64(100), nil},
		/* 36 */ {`1E+x`, sym.SymError, errors.New("[1:5] expected integer exponent, got x"), nil},
		/* 37 */ {`$`, sym.SymDollar, nil, nil},
		/* 38 */ {`\`, sym.SymError, errors.New("incomplete escape sequence"), nil},
		/* 39 */ {`"string"`, sym.SymString, "string", nil},
		/* 40 */ {`identifier`, sym.SymIdentifier, "identifier", nil},
	}

	for i, input := range inputs {
		// if i != 40 {
		// 	continue
		// }
		if input.wantErr == nil {
			t.Logf("[+]Test nr %2d -- %q", i+1, input.source)
		} else {
			t.Logf("[-]Test nr %2d -- %q", i+1, input.source)
		}

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

		if tk := scanner.Next(); tk == nil {
			t.Errorf("%d: %q -> got = (nil), want %v (value %v [%T])", i+1, input.source, input.wantSym, input.wantValue, input.wantValue)
			// } else if tk.Sym != input.wantSym || tk.Value != input.wantValue {
		} else if tk.Sym != input.wantSym || !reflect.DeepEqual(tk.Value, input.wantValue) {
			if tk.Sym == sym.SymError && input.wantSym == tk.Sym {
				if tkErr, tkOk := tk.Value.(error); tkOk {
					if inputErr, inputOk := input.wantValue.(error); inputOk {
						if tkErr.Error() != inputErr.Error() {
							t.Errorf("%d: %q -> got-error = %v, want-error: %v", i+1,
								input.source, tk.Value, input.wantValue)
						}
					}
				}
			} else {
				t.Errorf("%d: %q -> got = %v (value=%v [%T]), want %v (value=%v [%T])", i+1,
					input.source, tk.Sym, tk.Value, tk.Value, input.wantSym, input.wantValue, input.wantValue)
			}
		}
	}
}
