package parser

import "testing"

func TestLexerQuotedIdentifier(t *testing.T) {
	input := `SELECT "MyTable"."MyColumn" FROM "MyTable"`
	lexer := NewLexer(input)

	expected := []struct {
		typ    TokenType
		value  string
		quoted bool
	}{
		{TokenSelect, "", false},
		{TokenIdentifier, "MyTable", true},
		{TokenDot, "", false},
		{TokenIdentifier, "MyColumn", true},
		{TokenFrom, "", false},
		{TokenIdentifier, "MyTable", true},
		{TokenEOF, "", false},
	}

	for i, exp := range expected {
		token := lexer.NextToken()
		if token.Type != exp.typ {
			t.Fatalf("token %d: expected %v, got %v (%q)", i, exp.typ, token.Type, token.Value)
		}
		if exp.value != "" && token.Value != exp.value {
			t.Fatalf("token %d: expected value %q, got %q", i, exp.value, token.Value)
		}
		if token.Quoted != exp.quoted {
			t.Fatalf("token %d: expected quoted=%v, got %v", i, exp.quoted, token.Quoted)
		}
	}
}

func TestLexerDollarString(t *testing.T) {
	input := "SELECT $$a'b$$ FROM t"
	lexer := NewLexer(input)

	// SELECT
	if token := lexer.NextToken(); token.Type != TokenSelect {
		t.Fatalf("expected SELECT, got %v", token.Type)
	}
	// $$ string
	token := lexer.NextToken()
	if token.Type != TokenString {
		t.Fatalf("expected string literal, got %v", token.Type)
	}
	if token.Value != "a'b" {
		t.Fatalf("expected string value %q, got %q", "a'b", token.Value)
	}
	// FROM t
	if token = lexer.NextToken(); token.Type != TokenFrom {
		t.Fatalf("expected FROM, got %v", token.Type)
	}
	if token = lexer.NextToken(); token.Type != TokenIdentifier || token.Value != "t" {
		t.Fatalf("expected identifier t, got %v (%q)", token.Type, token.Value)
	}
}

func TestLexerLineCommentSlash(t *testing.T) {
	input := "SELECT * FROM t // comment\nWHERE id = 1"
	lexer := NewLexer(input)

	expectedTypes := []TokenType{
		TokenSelect,
		TokenAsterisk,
		TokenFrom,
		TokenIdentifier,
		TokenWhere,
		TokenIdentifier,
		TokenEqual,
		TokenInteger,
		TokenEOF,
	}

	for i, expected := range expectedTypes {
		token := lexer.NextToken()
		if token.Type != expected {
			t.Fatalf("token %d: expected %v, got %v (%q)", i, expected, token.Type, token.Value)
		}
	}
}

func TestLexerNamedBindMarkerTokens(t *testing.T) {
	input := "SELECT * FROM t WHERE id = :user_id"
	lexer := NewLexer(input)

	for {
		token := lexer.NextToken()
		if token.Type == TokenColon {
			next := lexer.NextToken()
			if next.Type != TokenIdentifier || next.Value != "user_id" {
				t.Fatalf("expected named marker identifier user_id, got %v (%q)", next.Type, next.Value)
			}
			return
		}
		if token.Type == TokenEOF {
			t.Fatal("expected ':' token for named bind marker, got EOF")
		}
	}
}

func TestLexerTypeHintToken(t *testing.T) {
	input := "SELECT * FROM t WHERE id = 1::uuid"
	lexer := NewLexer(input)

	found := false
	for {
		token := lexer.NextToken()
		if token.Type == TokenTypeHint {
			next := lexer.NextToken()
			if next.Type != TokenUUIDType {
				t.Fatalf("expected UUID type after type hint, got %v (%q)", next.Type, next.Value)
			}
			found = true
			break
		}
		if token.Type == TokenEOF {
			break
		}
	}

	if !found {
		t.Fatal("expected type hint token, got none")
	}
}
