package parser

import (
	"testing"
)

func TestLexerSelect(t *testing.T) {
	input := "SELECT id, name FROM users WHERE id = 1"
	lexer := NewLexer(input)

	expectedTypes := []TokenType{
		TokenSelect,
		TokenIdentifier, // id
		TokenComma,
		TokenIdentifier, // name
		TokenFrom,
		TokenUsers, // users
		TokenWhere,
		TokenIdentifier, // id
		TokenEqual,
		TokenInteger, // 1
		TokenEOF,
	}

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

func TestLexerStringLiteral(t *testing.T) {
	input := "SELECT * FROM users WHERE name = 'John'"
	lexer := NewLexer(input)

	// Skip to string literal
	for {
		token := lexer.NextToken()
		if token.Type == TokenString {
			if token.Value != "John" {
				t.Errorf("String value mismatch: expected 'John', got %s", token.Value)
			}
			return
		}
		if token.Type == TokenEOF {
			t.Error("Expected string token, got EOF")
			return
		}
	}
}

func TestParserSelect(t *testing.T) {
	tests := []struct {
		name  string
		input string
		want  string
	}{
		{
			name:  "simple select",
			input: "SELECT id, name FROM users",
			want:  "SELECT",
		},
		{
			name:  "select with where",
			input: "SELECT * FROM users WHERE id = 1",
			want:  "SELECT",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			parser := NewParser(tt.input)
			stmt, err := parser.Parse()
			if err != nil && stmt != nil {
				t.Logf("Parse completed with warnings: %v", err)
			}
			if stmt == nil {
				t.Fatalf("Expected statement, got nil: %v", err)
			}
			if stmt.String()[:6] != tt.want {
				t.Errorf("Expected %s statement, got %s", tt.want, stmt.String()[:6])
			}
		})
	}
}

func TestParserInsert(t *testing.T) {
	input := "INSERT INTO users (id, name) VALUES (1, 'John')"
	parser := NewParser(input)
	stmt, err := parser.Parse()
	if err != nil && stmt != nil {
		t.Logf("Parse completed with warnings: %v", err)
	}
	if stmt == nil {
		t.Fatalf("Parse failed: %v", err)
	}
	insert, ok := stmt.(*InsertStatement)
	if !ok {
		t.Fatalf("Expected InsertStatement, got %T", stmt)
	}
	if insert.Table.Name != "users" {
		t.Errorf("Expected table 'users', got %s", insert.Table.Name)
	}
}

func TestParserCreateTable(t *testing.T) {
	input := "CREATE TABLE users (id UUID PRIMARY KEY, name TEXT)"
	parser := NewParser(input)
	stmt, err := parser.Parse()
	if err != nil && stmt != nil {
		t.Logf("Parse completed with warnings: %v", err)
	}
	if stmt == nil {
		t.Fatalf("Parse failed: %v", err)
	}
	create, ok := stmt.(*CreateTableStatement)
	if !ok {
		t.Fatalf("Expected CreateTableStatement, got %T", stmt)
	}
	if create.Name.Name != "users" {
		t.Errorf("Expected table 'users', got %s", create.Name.Name)
	}
}

func TestParserUserDDL(t *testing.T) {
	tests := []struct {
		name  string
		input string
		check func(*testing.T, Statement)
	}{
		{
			name:  "create user",
			input: "CREATE USER IF NOT EXISTS alice WITH PASSWORD 'secret' NOSUPERUSER",
			check: func(t *testing.T, stmt Statement) {
				create, ok := stmt.(*CreateUserStatement)
				if !ok {
					t.Fatalf("Expected CreateUserStatement, got %T", stmt)
				}
				if !create.IfNotExists || create.Name != "alice" || create.Password != "secret" {
					t.Fatalf("unexpected CREATE USER parse: %+v", create)
				}
				if create.Superuser == nil || *create.Superuser {
					t.Fatalf("expected NOSUPERUSER")
				}
			},
		},
		{
			name:  "alter user",
			input: "ALTER USER IF EXISTS 'quoted-user' WITH PASSWORD 'new-secret'",
			check: func(t *testing.T, stmt Statement) {
				alter, ok := stmt.(*AlterUserStatement)
				if !ok {
					t.Fatalf("Expected AlterUserStatement, got %T", stmt)
				}
				if !alter.IfExists || alter.Name != "quoted-user" || alter.Password == nil || *alter.Password != "new-secret" {
					t.Fatalf("unexpected ALTER USER parse: %+v", alter)
				}
			},
		},
		{
			name:  "drop user",
			input: "DROP USER IF EXISTS bob",
			check: func(t *testing.T, stmt Statement) {
				drop, ok := stmt.(*DropUserStatement)
				if !ok {
					t.Fatalf("Expected DropUserStatement, got %T", stmt)
				}
				if !drop.IfExists || drop.Name != "bob" {
					t.Fatalf("unexpected DROP USER parse: %+v", drop)
				}
			},
		},
		{
			name:  "list users",
			input: "LIST USERS",
			check: func(t *testing.T, stmt Statement) {
				if _, ok := stmt.(*ListUsersStatement); !ok {
					t.Fatalf("Expected ListUsersStatement, got %T", stmt)
				}
			},
		},
		{
			name:  "grant keyspace",
			input: "GRANT ALL PERMISSIONS ON KEYSPACE chat_test TO verify_user_001",
			check: func(t *testing.T, stmt Statement) {
				grant, ok := stmt.(*GrantStatement)
				if !ok {
					t.Fatalf("Expected GrantStatement, got %T", stmt)
				}
				if grant.Keyspace != "chat_test" || grant.Role != "verify_user_001" {
					t.Fatalf("unexpected GRANT target: %+v", grant)
				}
				if len(grant.Permissions) != 1 || grant.Permissions[0] != "ALL" {
					t.Fatalf("unexpected GRANT permissions: %+v", grant.Permissions)
				}
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			stmt, err := NewParser(tt.input).Parse()
			if err != nil {
				t.Fatalf("Parse failed: %v", err)
			}
			tt.check(t, stmt)
		})
	}
}
