package parser

import (
	"fmt"
	"mars/ast"
	"mars/lexer"
	"testing"
)

func TestReturnStatements(t *testing.T) {
	tests := []struct {
		input         string
		expectedValue interface{}
	}{
		{"return 5;", 5},
		{"return true;", true},
		{"return foobar;", "foobar"},
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Declarations) != 1 {
			t.Fatalf("program.Declarations does not contain 1 statement. got=%d",
				len(program.Declarations))
		}

		stmt := program.Declarations[0]
		returnStmt, ok := stmt.(*ast.ReturnStatement)
		if !ok {
			t.Fatalf("stmt not *ast.ReturnStatement. got=%T", stmt)
		}
		if returnStmt.TokenLiteral() != "return" {
			t.Errorf("returnStmt.TokenLiteral not 'return', got %q",
				returnStmt.TokenLiteral())
		}
		if testLiteralExpression(t, returnStmt.Value, tt.expectedValue) {
			return
		}
	}
}

func TestForInitMutabilityParsing(t *testing.T) {
	cases := []struct {
		code        string
		wantMutable bool
		name        string
	}{
		{code: "for i := 0; i < 2; i = i + 1 { }", wantMutable: false, name: "no mut"},
		{code: "for mut i := 0; i < 2; i = i + 1 { }", wantMutable: true, name: "with mut"},
	}
	for _, tc := range cases {
		l := lexer.New(tc.code)
		p := NewParser(l)
		prog := p.ParseProgram()
		checkParserErrors(t, p)
		if len(prog.Declarations) != 1 {
			t.Fatalf("%s: expected 1 top-level decl, got %d", tc.name, len(prog.Declarations))
		}
		forStmt, ok := prog.Declarations[0].(*ast.ForStatement)
		if !ok {
			t.Fatalf("%s: top-level decl not *ast.ForStatement, got %T", tc.name, prog.Declarations[0])
		}
		if forStmt.Init == nil {
			t.Fatalf("%s: for.Init is nil", tc.name)
		}
		varDecl, ok := forStmt.Init.(*ast.VarDecl)
		if !ok {
			t.Fatalf("%s: for.Init not *ast.VarDecl, got %T", tc.name, forStmt.Init)
		}
		if varDecl.Mutable != tc.wantMutable {
			t.Fatalf("%s: Mutable mismatch: want %v, got %v", tc.name, tc.wantMutable, varDecl.Mutable)
		}
	}
}

func TestIdentifierExpression(t *testing.T) {
	input := "x := foobar;"

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()
	checkParserErrors(t, p)

	if len(program.Declarations) != 1 {
		t.Fatalf("program has not enough statements. got=%d",
			len(program.Declarations))
	}
	stmt, ok := program.Declarations[0].(*ast.VarDecl)
	if !ok {
		t.Fatalf("program.Declarations[0] is not ast.VarDecl. got=%T",
			program.Declarations[0])
	}

	ident, ok := stmt.Value.(*ast.Identifier)
	if !ok {
		t.Fatalf("exp not *ast.Identifier. got=%T", stmt.Value)
	}
	if ident.Name != "foobar" {
		t.Errorf("ident.Name not %s. got=%s", "foobar", ident.Name)
	}
	if ident.TokenLiteral() != "foobar" {
		t.Errorf("ident.TokenLiteral not %s. got=%s", "foobar",
			ident.TokenLiteral())
	}
}

func TestVariableDeclarations(t *testing.T) {
	tests := []struct {
		input              string
		expectedIdentifier string
		expectedType       string
		expectedValue      interface{}
	}{
		{"x := 5;", "x", "", 5},                                     // type inference
		{"x : int = 5;", "x", "int", 5},                             // explicit type
		{"mut y := 10.5;", "y", "", 10.5},                           // mutable with inference
		{"mut y : float = 10.5;", "y", "float", 10.5},               // mutable with explicit type
		{"name := \"John\";", "name", "", "\"John\""},               // string with inference
		{"name : string = \"John\";", "name", "string", "\"John\""}, // string with explicit type
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Declarations) != 1 {
			t.Fatalf("program.Declarations does not contain 1 declaration. got=%d",
				len(program.Declarations))
		}

		stmt := program.Declarations[0]
		if !testVariableDeclaration(t, stmt, tt.expectedIdentifier, tt.expectedType, tt.expectedValue) {
			return
		}
	}
}

func TestIntegerLiteralExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{"x := 5;", 5},            // type inference
		{"x : int = 5;", 5},       // explicit type
		{"mut y := 42;", 42},      // mutable with inference
		{"mut y : int = 42;", 42}, // mutable with explicit type
		{"return 100;", 100},      // in return statement
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Declarations) != 1 {
			t.Fatalf("program has not enough declarations. got=%d",
				len(program.Declarations))
		}

		var expr ast.Expression
		switch stmt := program.Declarations[0].(type) {
		case *ast.VarDecl:
			expr = stmt.Value
		case *ast.ReturnStatement:
			expr = stmt.Value
		default:
			t.Fatalf("unexpected declaration type. got=%T", program.Declarations[0])
		}

		literal, ok := expr.(*ast.Literal)
		if !ok {
			t.Fatalf("expr not *ast.Literal. got=%T", expr)
		}
		if literal.Value != tt.expected {
			t.Errorf("literal.Value not %d. got=%d", tt.expected, literal.Value)
		}
		if literal.TokenLiteral() != fmt.Sprintf("%d", tt.expected) {
			t.Errorf("literal.TokenLiteral not %s. got=%s",
				fmt.Sprintf("%d", tt.expected), literal.TokenLiteral())
		}
	}
}

func TestParsingPrefixExpressions(t *testing.T) {
	prefixTests := []struct {
		input    string
		operator string
		value    interface{}
	}{
		{"x := !true;", "!", true},
		{"x := !5;", "!", 5},
		{"x := -15;", "-", 15},
		{"x := !false;", "!", false},
	}

	for _, tt := range prefixTests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Declarations) != 1 {
			t.Fatalf("program.Declarations does not contain %d statements. got=%d\n",
				1, len(program.Declarations))
		}

		stmt, ok := program.Declarations[0].(*ast.VarDecl)
		if !ok {
			t.Fatalf("program.Declarations[0] is not ast.VarDecl. got=%T",
				program.Declarations[0])
		}

		exp, ok := stmt.Value.(*ast.UnaryExpression)
		if !ok {
			t.Fatalf("stmt.Value is not ast.UnaryExpression. got=%T", stmt.Value)
		}
		if exp.Operator != tt.operator {
			t.Fatalf("exp.Operator is not '%s'. got=%s",
				tt.operator, exp.Operator)
		}
		if !testLiteralExpression(t, exp.Right, tt.value) {
			return
		}
	}
}

func TestParsingInfixExpressions(t *testing.T) {
	infixTests := []struct {
		input      string
		leftValue  interface{}
		operator   string
		rightValue interface{}
	}{
		{"x := 5 + 5;", 5, "+", 5},
		{"x := 5 - 5;", 5, "-", 5},
		{"x := 5 * 5;", 5, "*", 5},
		{"x := 5 / 5;", 5, "/", 5},
		{"x := 5 > 5;", 5, ">", 5},
		{"x := 5 < 5;", 5, "<", 5},
		{"x := 5 == 5;", 5, "==", 5},
		{"x := 5 != 5;", 5, "!=", 5},
		{"x := true == true;", true, "==", true},
		{"x := true != false;", true, "!=", false},
		{"x := false == false;", false, "==", false},
	}

	for _, tt := range infixTests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Declarations) != 1 {
			t.Fatalf("program.Declarations does not contain %d statements. got=%d\n",
				1, len(program.Declarations))
		}

		stmt, ok := program.Declarations[0].(*ast.VarDecl)
		if !ok {
			t.Fatalf("program.Declarations[0] is not ast.VarDecl. got=%T",
				program.Declarations[0])
		}

		exp, ok := stmt.Value.(*ast.BinaryExpression)
		if !ok {
			t.Fatalf("exp is not ast.BinaryExpression. got=%T", stmt.Value)
		}

		if !testLiteralExpression(t, exp.Left, tt.leftValue) {
			return
		}

		if exp.Operator != tt.operator {
			t.Fatalf("exp.Operator is not '%s'. got=%s",
				tt.operator, exp.Operator)
		}

		if !testLiteralExpression(t, exp.Right, tt.rightValue) {
			return
		}
	}
}

func TestSimpleNumber(t *testing.T) {
	input := "42"
	l := lexer.New(input)
	tok := l.NextToken()

	t.Logf("Token Type: %s", tok.Type.String())
	t.Logf("Token Literal: %q", tok.Literal)
	t.Logf("Token Literal Length: %d", len(tok.Literal))

	if tok.Type != lexer.NUMBER {
		t.Errorf("Expected NUMBER token, got %s", tok.Type.String())
	}

	if tok.Literal != "42" {
		t.Errorf("Expected literal '42', got %q", tok.Literal)
	}
}

func TestNumberReadingFix(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"42", "42"},
		{"123", "123"},
		{"0", "0"},
		{"3.14", "3.14"},
		{"123.456", "123.456"},
		{"999", "999"},
	}

	for _, tt := range tests {
		t.Run(tt.input, func(t *testing.T) {
			l := lexer.New(tt.input)
			tok := l.NextToken()

			if tok.Type != lexer.NUMBER {
				t.Fatalf("Expected NUMBER token, got %s", tok.Type.String())
			}

			if tok.Literal != tt.expected {
				t.Errorf("Expected %q, got %q", tt.expected, tok.Literal)
			}

			// Make sure we consumed the entire number
			nextTok := l.NextToken()
			if nextTok.Type != lexer.EOF {
				t.Errorf("Expected EOF after number, got %s with literal %q",
					nextTok.Type.String(), nextTok.Literal)
			}
		})
	}
}

func TestOperatorPrecedenceParsing(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{
			"x := -a * b",
			"((-a) * b)", // Unary binds tighter than binary
		},
		{
			"x := !-a",
			"(!(-a))", // Right-associative unary operators
		},
		{
			"x := a + b + c",
			"((a + b) + c)", // Left-associative
		},
		{
			"x := a + b - c",
			"((a + b) - c)", // Left-associative
		},
		{
			"x := a * b * c",
			"((a * b) * c)", // Left-associative
		},
		{
			"x := a * b / c",
			"((a * b) / c)", // Left-associative
		},
		{
			"x := a + b / c",
			"(a + (b / c))", // * / bind tighter than + -
		},
		{
			"x := a + b * c + d / e - f",
			"(((a + (b * c)) + (d / e)) - f)", // Complex precedence
		},
		{
			"x := 3 + 4",
			"(3 + 4)",
		},
		{
			"x := -5 * 5",
			"((-5) * 5)", // Unary minus binds tighter
		},
		{
			"x := 5 > 4 == 3 < 4",
			"((5 > 4) == (3 < 4))", // Comparison binds tighter than equality
		},
		{
			"x := 5 < 4 != 3 > 4",
			"((5 < 4) != (3 > 4))", // Comparison binds tighter than equality
		},
		{
			"x := 3 + 4 * 5 == 3 * 1 + 4 * 5",
			"((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))", // Arithmetic before equality
		},
		{
			"x := true",
			"true", // Simple literal
		},
		{
			"x := false",
			"false", // Simple literal
		},
		{
			"x := 3 > 5 == false",
			"((3 > 5) == false)", // Comparison before equality
		},
		{
			"x := 3 < 5 == true",
			"((3 < 5) == true)", // Comparison before equality
		},
		{
			"x := 1 + (2 + 3) + 4",
			"((1 + (2 + 3)) + 4)", // Parentheses override precedence
		},
		{
			"x := (5 + 5) * 2",
			"((5 + 5) * 2)", // Parentheses first
		},
		{
			"x := 2 / (5 + 5)",
			"(2 / (5 + 5))", // Parentheses first
		},
		{
			"x := -(5 + 5)",
			"(-(5 + 5))", // Unary operator
		},
		{
			"x := !(true == true)",
			"(!(true == true))", // Unary operator
		},
		{
			"x := a + add(b * c) + d",
			"((a + add((b * c))) + d)", // Function calls are primary expressions
		},
		{
			"x := add(a, b, 1, 2 * 3, 4 + 5, add(6, 7 * 8))",
			"add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 * 8)))", // Function arguments
		},
		{
			"x := add(a + b + c * d / f + g)",
			"add((((a + b) + ((c * d) / f)) + g))", // Complex expression as argument
		},
	}

	for i, tt := range tests {
		t.Run(tt.input, func(t *testing.T) {
			l := lexer.New(tt.input)
			p := NewParser(l)
			program := p.ParseProgram()
			checkParserErrors(t, p)

			if len(program.Declarations) != 1 {
				t.Fatalf("program.Declarations does not contain 1 declaration. got=%d",
					len(program.Declarations))
			}

			// Safe type assertion with error checking
			stmt, ok := program.Declarations[0].(*ast.VarDecl)
			if !ok {
				t.Fatalf("program.Declarations[0] is not *ast.VarDecl. got=%T",
					program.Declarations[0])
			}

			if stmt.Value == nil {
				t.Fatalf("stmt.Value is nil")
			}

			actual := stmt.Value.String()
			if actual != tt.expected {
				t.Errorf("Test %d failed.\nInput: %s\nExpected: %q\nGot: %q",
					i+1, tt.input, tt.expected, actual)
			}
		})
	}
}

func TestIfExpression(t *testing.T) {
	input := `if (x < y) { x }`

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()
	checkParserErrors(t, p)

	if len(program.Declarations) != 1 {
		t.Fatalf("program.Declarations does not contain %d statements. got=%d\n",
			1, len(program.Declarations))
	}

	stmt, ok := program.Declarations[0].(*ast.IfStatement)
	if !ok {
		t.Fatalf("program.Declarations[0] is not ast.IfStatement. got=%T",
			program.Declarations[0])
	}

	if !testInfixExpression(t, stmt.Condition, "x", "<", "y") {
		return
	}

	if len(stmt.Consequence.Statements) != 1 {
		t.Errorf("consequence is not 1 statements. got=%d\n",
			len(stmt.Consequence.Statements))
	}

	consequence, ok := stmt.Consequence.Statements[0].(*ast.ExpressionStatement)
	if !ok {
		t.Fatalf("Statements[0] is not ast.ExpressionStatement. got=%T",
			stmt.Consequence.Statements[0])
	}

	if !testIdentifier(t, consequence.Expression, "x") {
		return
	}

	if stmt.Alternative != nil {
		t.Errorf("stmt.Alternative.Statements was not nil. got=%+v", stmt.Alternative)
	}
}

func TestFunctionLiteralParsing(t *testing.T) {
	input := `func add(x : int, y : int) { x + y; }`

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()
	checkParserErrors(t, p)

	if len(program.Declarations) != 1 {
		t.Fatalf("program.Declarations does not contain %d statements. got=%d\n",
			1, len(program.Declarations))
	}

	stmt, ok := program.Declarations[0].(*ast.FuncDecl)
	if !ok {
		t.Fatalf("program.Declarations[0] is not ast.FuncDecl. got=%T",
			program.Declarations[0])
	}

	if len(stmt.Signature.Parameters) != 2 {
		t.Fatalf("function parameters wrong. want 2, got=%d\n",
			len(stmt.Signature.Parameters))
	}

	testLiteralExpression(t, stmt.Signature.Parameters[0].Name, "x")
	testLiteralExpression(t, stmt.Signature.Parameters[1].Name, "y")

	if len(stmt.Body.Statements) != 1 {
		t.Fatalf("function.Body.Statements has not 1 statements. got=%d\n",
			len(stmt.Body.Statements))
	}

	bodyStmt, ok := stmt.Body.Statements[0].(*ast.ExpressionStatement)
	if !ok {
		t.Fatalf("function body stmt is not ast.ExpressionStatement. got=%T",
			stmt.Body.Statements[0])
	}

	testInfixExpression(t, bodyStmt.Expression, "x", "+", "y")
}

func TestFunctionParameterParsing(t *testing.T) {
	tests := []struct {
		input          string
		expectedParams []struct {
			name string
			typ  string
		}
	}{
		{
			input: "func empty() -> void {};",
			expectedParams: []struct {
				name string
				typ  string
			}{},
		},
		{
			input: "func single(x : int) -> int {};",
			expectedParams: []struct {
				name string
				typ  string
			}{
				{name: "x", typ: "int"},
			},
		},
		{
			input: "func multi(x : int, y : string, z : bool) -> void {}",
			expectedParams: []struct {
				name string
				typ  string
			}{
				{name: "x", typ: "int"},
				{name: "y", typ: "string"},
				{name: "z", typ: "bool"},
			},
		},
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		stmt := program.Declarations[0].(*ast.FuncDecl)

		if len(stmt.Signature.Parameters) != len(tt.expectedParams) {
			t.Errorf("length parameters wrong. want %d, got=%d\n",
				len(tt.expectedParams), len(stmt.Signature.Parameters))
		}

		for i, param := range tt.expectedParams {
			if stmt.Signature.Parameters[i].Name.Name != param.name {
				t.Errorf("parameter %d name wrong. want %s, got=%s\n",
					i, param.name, stmt.Signature.Parameters[i].Name.Name)
			}
			if stmt.Signature.Parameters[i].Type.BaseType != param.typ {
				t.Errorf("parameter %d type wrong. want %s, got=%s\n",
					i, param.typ, stmt.Signature.Parameters[i].Type.BaseType)
			}
		}
	}
}

func TestCallExpressionParsing(t *testing.T) {
	input := "x := add(1, 2 * 3, 4 + 5);"

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()
	checkParserErrors(t, p)

	if len(program.Declarations) != 1 {
		t.Fatalf("program.Declarations does not contain %d statements. got=%d\n",
			1, len(program.Declarations))
	}

	stmt, ok := program.Declarations[0].(*ast.VarDecl)
	if !ok {
		t.Fatalf("stmt is not ast.VarDecl. got=%T",
			program.Declarations[0])
	}

	exp, ok := stmt.Value.(*ast.FunctionCall)
	if !ok {
		t.Fatalf("stmt.Value is not ast.FunctionCall. got=%T",
			stmt.Value)
	}

	if !testIdentifier(t, exp.Function, "add") {
		return
	}

	if len(exp.Arguments) != 3 {
		t.Fatalf("wrong length of arguments. got=%d", len(exp.Arguments))
	}

	testLiteralExpression(t, exp.Arguments[0], 1)
	testInfixExpression(t, exp.Arguments[1], 2, "*", 3)
	testInfixExpression(t, exp.Arguments[2], 4, "+", 5)
}

func TestStructDeclaration(t *testing.T) {
	tests := []struct {
		input    string
		expected struct {
			name   string
			fields []struct {
				name string
				typ  string
			}
		}
	}{
		{
			input: `struct Point {
				x : int;
				y : int;
			}`,
			expected: struct {
				name   string
				fields []struct {
					name string
					typ  string
				}
			}{
				name: "Point",
				fields: []struct {
					name string
					typ  string
				}{
					{name: "x", typ: "int"},
					{name: "y", typ: "int"},
				},
			},
		},
		{
			input: `struct Person {
				name : string;
				age : int;
				active : bool;
			}`,
			expected: struct {
				name   string
				fields []struct {
					name string
					typ  string
				}
			}{
				name: "Person",
				fields: []struct {
					name string
					typ  string
				}{
					{name: "name", typ: "string"},
					{name: "age", typ: "int"},
					{name: "active", typ: "bool"},
				},
			},
		},
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Declarations) != 1 {
			t.Fatalf("program.Declarations does not contain 1 statement. got=%d",
				len(program.Declarations))
		}

		stmt := program.Declarations[0]
		structDecl, ok := stmt.(*ast.StructDecl)
		if !ok {
			t.Fatalf("stmt not *ast.StructDecl. got=%T", stmt)
		}

		if structDecl.Name.Name != tt.expected.name {
			t.Errorf("structDecl.Name.Name not %s. got=%s",
				tt.expected.name, structDecl.Name.Name)
		}

		if len(structDecl.Fields) != len(tt.expected.fields) {
			t.Fatalf("structDecl.Fields length not %d. got=%d",
				len(tt.expected.fields), len(structDecl.Fields))
		}

		for i, field := range structDecl.Fields {
			expected := tt.expected.fields[i]
			if field.Name.Name != expected.name {
				t.Errorf("field.Name.Name not %s. got=%s",
					expected.name, field.Name.Name)
			}
			if field.Type.BaseType != expected.typ {
				t.Errorf("field.Type.BaseType not %s. got=%s",
					expected.typ, field.Type.BaseType)
			}
		}
	}
}

func TestStructLiteral(t *testing.T) {
	tests := []struct {
		input    string
		expected struct {
			typeName string
			fields   []struct {
				name  string
				value interface{}
			}
		}
	}{
		{
			input: `x := Point{x: 5, y: 10};`,
			expected: struct {
				typeName string
				fields   []struct {
					name  string
					value interface{}
				}
			}{
				typeName: "Point",
				fields: []struct {
					name  string
					value interface{}
				}{
					{name: "x", value: 5},
					{name: "y", value: 10},
				},
			},
		},
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		if len(program.Declarations) != 1 {
			t.Fatalf("program.Declarations does not contain 1 statement. got=%d",
				len(program.Declarations))
		}

		stmt := program.Declarations[0]
		varDecl, ok := stmt.(*ast.VarDecl)
		if !ok {
			t.Fatalf("stmt not *ast.VarDecl. got=%T", stmt)
		}

		structLit, ok := varDecl.Value.(*ast.StructLiteral)
		if !ok {
			t.Fatalf("expr not *ast.StructLiteral. got=%T", varDecl.Value)
		}

		if structLit.Type.Name != tt.expected.typeName {
			t.Errorf("structLit.Type.Name not %s. got=%s",
				tt.expected.typeName, structLit.Type.Name)
		}

		if len(structLit.Fields) != len(tt.expected.fields) {
			t.Fatalf("structLit.Fields length not %d. got=%d",
				len(tt.expected.fields), len(structLit.Fields))
		}

		for i, field := range structLit.Fields {
			expected := tt.expected.fields[i]
			if field.Name.Name != expected.name {
				t.Errorf("field.Name.Name not %s. got=%s",
					expected.name, field.Name.Name)
			}
			if !testLiteralExpression(t, field.Value, expected.value) {
				return
			}
		}
	}
}

func TestVariableDeclarations_WithArrayTypes(t *testing.T) {
	tests := []struct {
		input     string
		varName   string
		arraySize *int
		elemType  string
		hasValue  bool
	}{
		{
			input:     `x : [5]int = [1, 2, 3, 4, 5]`,
			varName:   "x",
			arraySize: func() *int { i := 5; return &i }(),
			elemType:  "int",
			hasValue:  true,
		},
		{
			input:     `names : []string = ["Alice", "Bob"]`,
			varName:   "names",
			arraySize: nil, // slice
			elemType:  "string",
			hasValue:  true,
		},
		{
			input:     `mut buffer : [256]int`,
			varName:   "buffer",
			arraySize: func() *int { i := 256; return &i }(),
			elemType:  "int",
			hasValue:  false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.input, func(t *testing.T) {
			l := lexer.New(tt.input)
			p := NewParser(l)

			// Parse as a complete program
			program := p.ParseProgram()
			checkParserErrors(t, p)

			if len(program.Declarations) != 1 {
				t.Fatalf("expected 1 declaration, got=%d", len(program.Declarations))
			}

			// Should be a variable declaration
			varDecl, ok := program.Declarations[0].(*ast.VarDecl)
			if !ok {
				t.Fatalf("expected *ast.VarDecl, got=%T", program.Declarations[0])
			}

			// Check variable name
			if varDecl.Name.Name != tt.varName {
				t.Errorf("expected variable name=%s, got=%s", tt.varName, varDecl.Name.Name)
			}

			// Check type
			if varDecl.Type == nil {
				t.Fatalf("expected Type to be set")
			}

			// Check array size
			if tt.arraySize == nil {
				if varDecl.Type.ArraySize != nil {
					t.Errorf("expected ArraySize to be nil, got=%d", *varDecl.Type.ArraySize)
				}
			} else {
				if varDecl.Type.ArraySize == nil {
					t.Errorf("expected ArraySize to be %d, got=nil", *tt.arraySize)
				} else if *varDecl.Type.ArraySize != *tt.arraySize {
					t.Errorf("expected ArraySize=%d, got=%d", *tt.arraySize, *varDecl.Type.ArraySize)
				}
			}

			// Check element type
			if varDecl.Type.ArrayType == nil {
				t.Fatalf("expected ArrayType to be set")
			}
			if varDecl.Type.ArrayType.BaseType != tt.elemType {
				t.Errorf("expected BaseType=%s, got=%s", tt.elemType, varDecl.Type.ArrayType.BaseType)
			}

			// Check if value is present
			if tt.hasValue && varDecl.Value == nil {
				t.Errorf("expected Value to be set")
			}
			if !tt.hasValue && varDecl.Value != nil {
				t.Errorf("expected Value to be nil")
			}
		})
	}
}

func TestArrayLiteral(t *testing.T) {
	input := `x : []int = [1, 2 * 2, 3 + 3]`

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()
	checkParserErrors(t, p)

	stmt := program.Declarations[0].(*ast.VarDecl)
	array, ok := stmt.Value.(*ast.ArrayLiteral)
	if !ok {
		t.Fatalf("exp not *ast.ArrayLiteral. got=%T", stmt.Value)
	}

	if len(array.Elements) != 3 {
		t.Fatalf("len(array.Elements) not 3. got=%d", len(array.Elements))
	}

	testIntegerLiteralInt(t, array.Elements[0], 1)
	testInfixExpression(t, array.Elements[1], 2, "*", 2)
	testInfixExpression(t, array.Elements[2], 3, "+", 3)
}

func TestParsingArrayLiterals(t *testing.T) {
	tests := []struct {
		input    string
		expected []interface{}
	}{
		{
			input:    `x : []int = [1, 2, 3]`,
			expected: []interface{}{1, 2, 3},
		},
		{
			input:    `x : []string = ["hello", "world"]`,
			expected: []interface{}{"hello", "world"},
		},
		{
			input:    `x : []bool = [true, false]`,
			expected: []interface{}{true, false},
		},
		{
			input:    `x : []bool = [true, false, true]`,
			expected: []interface{}{true, false, true},
		},
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		program := p.ParseProgram()
		checkParserErrors(t, p)

		stmt := program.Declarations[0].(*ast.VarDecl)
		array, ok := stmt.Value.(*ast.ArrayLiteral)
		if !ok {
			t.Fatalf("exp not *ast.ArrayLiteral. got=%T", stmt.Value)
		}

		if len(array.Elements) != len(tt.expected) {
			t.Fatalf("len(array.Elements) not %d. got=%d",
				len(tt.expected), len(array.Elements))
		}

		for i, elem := range tt.expected {
			switch v := elem.(type) {
			case int:
				testIntegerLiteralInt(t, array.Elements[i], v)
			case string:
				testStringLiteral(t, array.Elements[i], v)
			case bool:
				testBooleanLiteral(t, array.Elements[i], v)
			}
		}
	}
}

func TestPointerType(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{`*int`, "int"},
		{`*string`, "string"},
		{`*bool`, "bool"},
	}

	for _, tt := range tests {
		l := lexer.New(tt.input)
		p := NewParser(l)
		typ := p.parseType()
		checkParserErrors(t, p)

		if typ == nil {
			t.Fatalf("parseType() returned nil")
		}

		if typ.PointerType == nil {
			t.Fatalf("typ.PointerType is nil")
		}

		if typ.PointerType.BaseType != tt.expected {
			t.Errorf("typ.PointerType.BaseType not %s. got=%s",
				tt.expected, typ.PointerType.BaseType)
		}
	}
}

// Debug version to see what's actually being parsed
func TestUnsafeBlockDebug(t *testing.T) {
	input := `unsafe { x := 42; log(x) }`

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()

	t.Logf("Parse errors: %v", p.GetErrors())
	t.Logf("Number of declarations: %d", len(program.Declarations))

	if len(program.Declarations) > 0 {
		decl := program.Declarations[0]
		t.Logf("Declaration type: %T", decl)

		if unsafeBlock, ok := decl.(*ast.UnsafeBlock); ok {
			t.Logf("Unsafe block body statements: %d", len(unsafeBlock.Body.Statements))
			for i, stmt := range unsafeBlock.Body.Statements {
				t.Logf("Statement %d: %T - %s", i, stmt, stmt.String())
			}
		}
	}
}

func TestUnsafeTokens(t *testing.T) {
	input := `unsafe { x := 42; log(x) }`

	l := lexer.New(input)

	fmt.Println("=== TOKEN STREAM ===")
	for {
		tok := l.NextToken()
		fmt.Printf("Type: %-12s Literal: %q\n", tok.Type.String(), tok.Literal)
		if tok.Type == lexer.EOF {
			break
		}
	}
}

func TestTokens(t *testing.T) {
	testCases := []string{
		"[256]int",
		"[]bool",
		"mut buffer : [256]int",
		"items := []bool",
		"int",    // Just the keyword alone
		"bool",   // Just the keyword alone
		"string", // Test this too
		"float",  // And this
	}

	for _, test := range testCases {
		debugTokenStream(test)
	}

	// Let's also test the keyword lookup directly
	fmt.Println("Keyword Lookup Test:")
	fmt.Println("==================")

	keywords := []string{"int", "bool", "string", "float", "mut", "func"}
	for _, kw := range keywords {
		tokType := lexer.LookupIdent(kw)
		fmt.Printf("LookupIdent(%q) = %s\n", kw, tokType.String())
	}
}

func TestBetterVarErrorTest(t *testing.T) {
	input := `var x : int = 5;`

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()

	errors := p.GetErrors()

	// The test should check the actual behavior:
	// 1. No parse errors (because it's syntactically valid)
	// 2. But semantically wrong (two declarations instead of one)

	t.Logf("Errors: %v", errors)
	t.Logf("Declarations: %d", len(program.Declarations))

	// What actually happens:
	// Declaration 0: ExpressionStatement with Identifier("var")
	// Declaration 1: VarDecl with name "x"

	if len(program.Declarations) != 2 {
		t.Errorf("Expected 2 declarations (var as expr + actual var), got %d",
			len(program.Declarations))
	}

	// First declaration should be expression statement with "var"
	if len(program.Declarations) >= 1 {
		if exprStmt, ok := program.Declarations[0].(*ast.ExpressionStatement); ok {
			if ident, ok := exprStmt.Expression.(*ast.Identifier); ok {
				if ident.Name != "var" {
					t.Errorf("Expected identifier 'var', got %q", ident.Name)
				} else {
					t.Logf("✅ 'var' parsed as identifier (as expected)")
				}
			}
		}
	}

	// Second declaration should be variable declaration
	if len(program.Declarations) >= 2 {
		if varDecl, ok := program.Declarations[1].(*ast.VarDecl); ok {
			if varDecl.Name.Name != "x" {
				t.Errorf("Expected variable name 'x', got %q", varDecl.Name.Name)
			} else {
				t.Logf("✅ Variable 'x' parsed correctly")
			}
		}
	}
}

func TestParserErrorsCorrected(t *testing.T) {
	tests := []struct {
		input       string
		shouldError bool
		errorCount  int
		description string
	}{
		{
			input:       `func add(a : int, b : int) int { return a + b; }`,
			shouldError: true,
			errorCount:  2, // Missing -> and unexpected RBRACE
			description: "function missing -> in return type",
		},
		{
			input:       `func test(x : int { return x; }`,
			shouldError: true,
			errorCount:  2, // Missing ) and unexpected RBRACE
			description: "function missing closing parenthesis",
		},
		{
			input:       `var x : int = 5;`,
			shouldError: false, // Actually parses successfully (as two declarations)
			errorCount:  0,
			description: "'var' parsed as identifier + separate variable declaration",
		},
		{
			input:       `x :=;`,
			shouldError: true,
			errorCount:  1, // EOF in expression
			description: "missing assignment value",
		},
		{
			input:       `p := Point{x: 1, y:};`,
			shouldError: true,
			errorCount:  3, // EOF in expression + missing RBRACE
			description: "parser state error: unexpected token '}' in expression (context: current token: '}', peek token: ';')",
		},
	}

	for _, tt := range tests {
		t.Run(tt.description, func(t *testing.T) {
			l := lexer.New(tt.input)
			p := NewParser(l)
			p.ParseProgram()

			errors := p.GetErrors()
			hasErrors := errors.HasErrors()

			if tt.shouldError && !hasErrors {
				t.Errorf("Expected errors but got none")
			}

			if !tt.shouldError && hasErrors {
				t.Errorf("Expected no errors but got: %v", errors)
			}

			if tt.errorCount > 0 && len(errors.Errors()) != tt.errorCount {
				t.Errorf("Expected %d errors, got %d: %v",
					tt.errorCount, len(errors.Errors()), errors)
			}
		})
	}
}

// Better approach: Test specific error conditions
func TestSpecificParserErrors(t *testing.T) {
	tests := []struct {
		input       string
		shouldError bool
		description string
	}{
		{
			input:       `x := 42;`,
			shouldError: false,
			description: "valid variable declaration",
		},
		{
			input:       `x :=;`,
			shouldError: true,
			description: "missing assignment value",
		},
		{
			input:       `func test() { return 42; }`,
			shouldError: false,
			description: "valid function declaration",
		},
		{
			input:       `func test( { return 42; }`,
			shouldError: true,
			description: "malformed function parameters",
		},
		{
			input:       `struct Point { x : int; }`,
			shouldError: false,
			description: "valid struct declaration",
		},
		{
			input:       `struct Point { x :; }`,
			shouldError: true,
			description: "missing field type",
		},
	}

	for _, tt := range tests {
		t.Run(tt.description, func(t *testing.T) {
			l := lexer.New(tt.input)
			p := NewParser(l)
			program := p.ParseProgram()

			errors := p.GetErrors()
			hasErrors := errors.HasErrors()

			t.Logf("Input: %s", tt.input)
			t.Logf("Errors: %v", errors)
			t.Logf("Declarations parsed: %d", len(program.Declarations))

			if tt.shouldError && !hasErrors {
				t.Errorf("Expected errors but got none")
			}

			if !tt.shouldError && hasErrors {
				t.Errorf("Expected no errors but got: %v", errors)
			}
		})
	}
}

// Debug test to see what errors your parser actually produces
func TestDebugParserErrors(t *testing.T) {
	inputs := []string{
		`struct Point { x : int y : int; }`,  // Missing semicolon
		`func add(a : int, b : int) int { }`, // Wrong return syntax
		`x :=`,                               // Incomplete assignment
		`func test( { }`,                     // Malformed function
		`var x : int = 5`,                    // Invalid 'var' keyword
	}

	for i, input := range inputs {
		t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
			l := lexer.New(input)
			p := NewParser(l)
			program := p.ParseProgram()

			errors := p.GetErrors()

			t.Logf("=== INPUT %d ===", i)
			t.Logf("Code: %s", input)
			t.Logf("Errors (%d): %v", len(errors.Errors()), errors)
			t.Logf("Declarations: %d", len(program.Declarations))
			t.Logf("")
		})
	}
}

func testVariableDeclaration(t *testing.T, s ast.Declaration, name string, expectedType string, expectedValue interface{}) bool {
	varDecl, ok := s.(*ast.VarDecl)
	if !ok {
		t.Errorf("s not *ast.VarDecl. got=%T", s)
		return false
	}

	if varDecl.Name.Name != name {
		t.Errorf("varDecl.Name.Name not '%s'. got=%s", name, varDecl.Name.Name)
		return false
	}

	if expectedType != "" && varDecl.Type.BaseType != expectedType {
		t.Errorf("varDecl.Type.BaseType not '%s'. got=%s", expectedType, varDecl.Type.BaseType)
		return false
	}

	if !testLiteralExpression(t, varDecl.Value, expectedValue) {
		return false
	}

	return true
}

// Helper functions for testing

func checkParserErrors(t *testing.T, p *parser) {
	if !p.errors.HasErrors() {
		return
	}

	t.Errorf("parser has %d errors", len(p.errors.Errors()))
	for _, err := range p.errors.Errors() {
		t.Errorf("parser error: %q", err.Error())
	}
	t.FailNow()
}

func testInfixExpression(t *testing.T, exp ast.Expression, left interface{},
	operator string, right interface{}) bool {

	opExp, ok := exp.(*ast.BinaryExpression)
	if !ok {
		t.Errorf("exp is not ast.BinaryExpression. got=%T(%s)", exp, exp)
		return false
	}

	if !testLiteralExpression(t, opExp.Left, left) {
		return false
	}

	if opExp.Operator != operator {
		t.Errorf("exp.Operator is not '%s'. got=%q", operator, opExp.Operator)
		return false
	}

	if !testLiteralExpression(t, opExp.Right, right) {
		return false
	}

	return true
}

func testLiteralExpression(t *testing.T, exp ast.Expression, expected interface{}) bool {
	switch v := expected.(type) {
	case int:
		return testIntegerLiteralInt(t, exp, v)
	case float64:
		return testIntegerLiteralFloat(t, exp, v)
	case string:
		// Check if it's a string literal (starts with quote) or an identifier
		if len(v) > 0 && v[0] == '"' {
			return testStringLiteral(t, exp, v[1:len(v)-1]) // Remove quotes
		}
		return testIdentifier(t, exp, v)
	case bool:
		return testBooleanLiteral(t, exp, v)
	}
	t.Errorf("type of exp not handled. got=%T", exp)
	return false
}

func testIntegerLiteralInt(t *testing.T, il ast.Expression, value int) bool {
	integ, ok := il.(*ast.Literal)
	if !ok {
		t.Errorf("il not *ast.Literal. got=%T", il)
		return false
	}

	intVal, ok := integ.Value.(int)
	if !ok {
		t.Errorf("integ.Value not int. got=%T", integ.Value)
		return false
	}

	if intVal != value {
		t.Errorf("integ.Value not %d. got=%d", value, intVal)
		return false
	}

	return true
}

func testIntegerLiteralFloat(t *testing.T, il ast.Expression, value float64) bool {
	integ, ok := il.(*ast.Literal)
	if !ok {
		t.Errorf("il not *ast.Literal. got=%T", il)
		return false
	}

	floatVal, ok := integ.Value.(float64)
	if !ok {
		t.Errorf("integ.Value not float64. got=%T", integ.Value)
		return false
	}

	if floatVal != value {
		t.Errorf("integ.Value not %f. got=%f", value, floatVal)
		return false
	}

	return true
}

func testIdentifier(t *testing.T, exp ast.Expression, value string) bool {
	ident, ok := exp.(*ast.Identifier)
	if !ok {
		t.Errorf("exp not *ast.Identifier. got=%T", exp)
		return false
	}

	if ident.Name != value {
		t.Errorf("ident.Name not %s. got=%s", value, ident.Name)
		return false
	}

	if ident.TokenLiteral() != value {
		t.Errorf("ident.TokenLiteral not %s. got=%s", value,
			ident.TokenLiteral())
		return false
	}

	return true
}

func testBooleanLiteral(t *testing.T, exp ast.Expression, value bool) bool {
	bo, ok := exp.(*ast.Literal)
	if !ok {
		t.Errorf("exp not *ast.Literal. got=%T", exp)
		return false
	}

	if bo.Value != value {
		t.Errorf("bo.Value not %t. got=%t", value, bo.Value)
		return false
	}

	return true
}

func testStringLiteral(t *testing.T, exp ast.Expression, value string) bool {
	str, ok := exp.(*ast.Literal)
	if !ok {
		t.Errorf("exp not *ast.Literal. got=%T", exp)
		return false
	}

	if str.Value != value {
		t.Errorf("str.Value not %s. got=%s", value, str.Value)
		return false
	}

	return true
}

func debugTokenStream(input string) {
	fmt.Printf("Input: %q\n", input)
	fmt.Println("Tokens:")
	fmt.Println("-------")

	l := lexer.New(input)
	for {
		tok := l.NextToken()
		fmt.Printf("Type: %-12s Literal: %q\n", tok.Type.String(), tok.Literal)

		if tok.Type == lexer.EOF {
			break
		}
	}
	fmt.Println()
}

/////////////////////////////////////////////////////
// Let's test each component separately

// Test 1: Can we parse variable declaration outside unsafe block?
func TestVariableDeclarationAlone(t *testing.T) {
	input := `x := 42`

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()

	errors := p.GetErrors()
	t.Logf("Errors: %v", errors)
	t.Logf("Declarations: %d", len(program.Declarations))

	if errors.HasErrors() {
		t.Fatalf("Variable declaration failed: %v", errors)
	}

	if len(program.Declarations) != 1 {
		t.Fatalf("Expected 1 declaration, got %d", len(program.Declarations))
	}

	decl := program.Declarations[0]
	t.Logf("Declaration type: %T", decl)

	if varDecl, ok := decl.(*ast.VarDecl); ok {
		t.Logf("✅ Variable name: %s", varDecl.Name.Name)
		if varDecl.Value != nil {
			t.Logf("✅ Variable value: %s", varDecl.Value.String())
		} else {
			t.Logf("❌ Variable value is nil")
		}
	} else {
		t.Fatalf("Expected *ast.VarDecl, got %T", decl)
	}
}

// Test 2: Can we parse log statement alone?
func TestLogStatementAlone(t *testing.T) {
	input := `log(x)`

	l := lexer.New(input)
	p := NewParser(l)
	program := p.ParseProgram()

	errors := p.GetErrors()
	t.Logf("Errors: %v", errors)
	t.Logf("Declarations: %d", len(program.Declarations))

	if errors.HasErrors() {
		t.Fatalf("Log statement failed: %v", errors)
	}

	if len(program.Declarations) != 1 {
		t.Fatalf("Expected 1 declaration, got %d", len(program.Declarations))
	}

	decl := program.Declarations[0]
	t.Logf("Declaration type: %T", decl)

	if printStmt, ok := decl.(*ast.PrintStatement); ok {
		t.Logf("✅ Print statement parsed")
		if printStmt.Expression != nil {
			t.Logf("✅ Expression: %s", printStmt.Expression.String())
		} else {
			t.Logf("❌ Expression is nil")
		}
	} else {
		t.Logf("Declaration is: %T", decl)
	}
}

// Test 3: Can we parse a simple block?
func TestSimpleBlock(t *testing.T) {
	input := `{ x := 42 }`

	l := lexer.New(input)
	p := NewParser(l)

	// Try to parse as block statement directly
	block := p.parseBlockStatement()
	errors := p.GetErrors()

	t.Logf("Errors: %v", errors)
	t.Logf("Block: %T", block)

	if block == nil {
		t.Fatal("Block is nil")
	}

	t.Logf("Block statements: %d", len(block.Statements))

	for i, stmt := range block.Statements {
		t.Logf("Statement %d: %T", i, stmt)
		if stmt != nil {
			// Add nil check before calling String()
			defer func() {
				if r := recover(); r != nil {
					t.Logf("PANIC in String() for statement %d: %v", i, r)
				}
			}()
			t.Logf("Statement %d string: %s", i, stmt.String())
		}
	}
}

// Test 4: Trace unsafe block parsing step by step
func TestUnsafeBlockStepByStep(t *testing.T) {
	input := `unsafe { x := 42 }`

	l := lexer.New(input)
	p := NewParser(l)

	// Check initial token
	t.Logf("Initial token: %s %q", p.curToken.Type.String(), p.curToken.Literal)

	// Should be UNSAFE
	if p.curToken.Type != lexer.UNSAFE {
		t.Fatalf("Expected UNSAFE token, got %s", p.curToken.Type.String())
	}

	// Try to parse unsafe declaration
	decl := p.parseDeclaration()
	errors := p.GetErrors()

	t.Logf("Parse errors: %v", errors)
	t.Logf("Declaration: %T", decl)

	if unsafeBlock, ok := decl.(*ast.UnsafeBlock); ok {
		t.Logf("✅ Unsafe block parsed")
		t.Logf("Body: %T", unsafeBlock.Body)

		if unsafeBlock.Body != nil {
			t.Logf("Body statements: %d", len(unsafeBlock.Body.Statements))

			for i, stmt := range unsafeBlock.Body.Statements {
				t.Logf("Statement %d: %T", i, stmt)

				// Safe string conversion
				if stmt != nil {
					defer func() {
						if r := recover(); r != nil {
							t.Logf("PANIC in statement %d String(): %v", i, r)
						}
					}()

					// Check if it's an ExpressionStatement with nil Expression
					if exprStmt, ok := stmt.(*ast.ExpressionStatement); ok {
						t.Logf("ExpressionStatement - Expression: %T", exprStmt.Expression)
						if exprStmt.Expression == nil {
							t.Logf("❌ ExpressionStatement has nil Expression!")
						} else {
							t.Logf("Expression string: %s", exprStmt.Expression.String())
						}
					}

					t.Logf("Statement string: %s", stmt.String())
				}
			}
		}
	} else if decl != nil {
		t.Logf("Got declaration type: %T", decl)
	} else {
		t.Logf("❌ Declaration is nil")
	}
}

// Test 5: Check if parseDeclaration works for individual components
func TestParseDeclarationComponents(t *testing.T) {
	tests := []string{
		"x := 42",
		"log(x)",
	}

	for _, test := range tests {
		t.Run(test, func(t *testing.T) {
			l := lexer.New(test)
			p := NewParser(l)

			t.Logf("Input: %s", test)
			t.Logf("Initial token: %s %q", p.curToken.Type.String(), p.curToken.Literal)

			decl := p.parseDeclaration()
			errors := p.GetErrors()

			t.Logf("Errors: %v", errors)
			t.Logf("Declaration: %T", decl)

			if errors.HasErrors() {
				t.Errorf("Failed to parse %s: %v", test, errors)
			}
		})
	}
}

func TestVarKeywordDebug(t *testing.T) {
	input := `var x : int = 5;`

	// First check tokens
	l := lexer.New(input)
	fmt.Println("=== TOKENS ===")
	for {
		tok := l.NextToken()
		fmt.Printf("Type: %-12s Literal: %q\n", tok.Type.String(), tok.Literal)
		if tok.Type == lexer.EOF {
			break
		}
	}

	// Then check parsing
	l2 := lexer.New(input)
	p := NewParser(l2)
	program := p.ParseProgram()

	fmt.Println("\n=== PARSING RESULTS ===")
	fmt.Printf("Errors: %v\n", p.GetErrors())
	fmt.Printf("Declarations: %d\n", len(program.Declarations))

	for i, decl := range program.Declarations {
		fmt.Printf("Declaration %d: %T\n", i, decl)

		if exprStmt, ok := decl.(*ast.ExpressionStatement); ok {
			fmt.Printf("  Expression: %T\n", exprStmt.Expression)
			if ident, ok := exprStmt.Expression.(*ast.Identifier); ok {
				fmt.Printf("  Identifier name: %q\n", ident.Name)
			}
		} else if varDecl, ok := decl.(*ast.VarDecl); ok {
			fmt.Printf("  Variable name: %q\n", varDecl.Name.Name)
		}
	}
}
