package muesli

import (
	"reflect"
	"runtime"
	_ "strings"
	"testing"
)

func LexText(input string) []Token {
	lexer := NewLexerFromString(input)
	tokens := lexer.LexAll()
	return tokens
}

func Assert(test *testing.T, ok bool, text string) bool {
	if !ok {
		test.Errorf(text)
	}
	return ok
}

func HelperTryLexText(input string, test *testing.T) {
	tokens := LexText(input)
	for i := 0; i < len(tokens); i++ {
		// test.Logf("%d: %s", i, tokens[i].String())
	}
}

func HelperLexExpect(input string, wantKind TokenKind, wantValue Value, test *testing.T) {
	lexer := NewLexerFromString(input)
	lexer.SetLogger(&testLogger{"", 0, test})
	token := lexer.Lex()
	if (token.TokenKind == wantKind) && (token.Value == wantValue) {
		/* test.Logf("Token as expected %v %v", token.TokenKind, token.Value) */
	} else {
		test.Errorf("Unexpected token kind or value: %v %v >%v< >%v<",
			token.TokenKind, wantKind, token.Value, wantValue)
	}
}

func HelperFunctionName(f interface{}) string {
	fp := reflect.ValueOf(f).Pointer()
	info := runtime.FuncForPC(fp)
	if info != nil {
		return info.Name()
	}
	return "unknown"
}

func HelperLexTestSkip(input string, want rune, call func(*Lexer) error, test *testing.T) {
	var r rune
	lexer := NewLexerFromString(input)
	lexer.SetLogger(&testLogger{"", 0, test})
	fn := HelperFunctionName(call)
	err := call(lexer)
	if err != nil {
		test.Errorf("Unexpected error result: %s: %v", fn, err)
	}
	r, err = lexer.Peek()
	if err != nil {
		test.Errorf("Unexpected error result on peek for %s: %v", fn, err)
	}
	if r != want {
		test.Errorf("Unexpected character peeked for %s: %c: %c", fn, r, want)
	}
}

func TestLexParts(test *testing.T) {
	HelperLexTestSkip(" abc", 'a', (*Lexer).SkipSpace, test)
	HelperLexTestSkip("     xyz", 'x', (*Lexer).SkipSpace, test)
	HelperLexTestSkip(" #  \nd", 'd', (*Lexer).SkipComment, test)
	HelperLexTestSkip("#{}e", 'e', (*Lexer).SkipComment, test)
	HelperLexTestSkip("#{{}{{}}}f", 'f', (*Lexer).SkipComment, test)
	HelperLexTestSkip("    \tword\n", 'w', (*Lexer).SkipSpace, test)
}

func TestLex(test *testing.T) {
	HelperLexExpect("word\n", TokenKindWord, StringValue("word"), test)
	HelperLexExpect(":symbol\n", TokenKindSymbol, StringValue("symbol"), test)
	HelperLexExpect("1234\n", TokenKindInteger, IntValue(1234), test)
	HelperLexExpect("-3.14\n", TokenKindFloat, FloatValue(-3.14), test)
	HelperLexExpect(`"Hello \"world" \n`, TokenKindString, StringValue(`Hello "world`), test)
	HelperLexExpect("true\n", TokenKindBoolean, TrueValue, test)
	HelperLexExpect("false\n", TokenKindBoolean, FalseValue, test)
	HelperLexExpect("    \tword\n", TokenKindWord, StringValue("word"), test)
	/*
		HelperLexExpect("# comment should be ignored\ntrue\n", TokenKindBoolean, TrueValue, test)
		HelperLexExpect("  # comment should be ignored\ntrue\n", TokenKindBoolean, TrueValue, test)
		HelperLexExpect("  # comment should be ignored\n  true\n", TokenKindBoolean, TrueValue, test)
		HelperLexExpect("#{ comment should be ignored\n this too } true\n", TokenKindBoolean, TrueValue, test)
	*/
}

func TestLexing(test *testing.T) {
	const input = `
    greet "hi there"
    
    add 5 10 
    mulf -2.0 3.1415
    say1 "unicode « ❤ 🂱"
    say2 "hello world"
    say3 "quote \" endquote"
    say4 "escape \a\b\e\f\n\r\t\"\\"
    say5 "numescape \xab \u2764 \U01f0b1"
    say_6 "hello \"world\\"
    :❤a_symbol❤

define open a door {
    set (door open) true
}

def increment variable by value {
    =variable (add variable $value)
}
`
	// HelperTryLexText(input, test)
}


func TestLexDesignFile(test *testing.T) {
	lexer, err := NewLexerFromFilename("design_muesli.muesli")
	if err != nil { 
        test.Errorf("Error parsing file : %s", err)
        return
    }
    if lexer == nil {
        test.Errorf("Error: lexer is nil.")
        return
    }
    defer lexer.Report()
    tokens := lexer.LexAll()
	for i := 0; i < len(tokens); i++ {
		test.Logf("%d: %s", i, tokens[i].String())
	}
}