package luajit

import (
	"math"
	"testing"
)

func TestTableOperations(t *testing.T) {
	tests := []struct {
		name string
		data map[string]interface{}
	}{
		{
			name: "empty",
			data: map[string]interface{}{},
		},
		{
			name: "primitives",
			data: map[string]interface{}{
				"str":   "hello",
				"num":   42.0,
				"bool":  true,
				"array": []float64{1.1, 2.2, 3.3},
			},
		},
		{
			name: "nested",
			data: map[string]interface{}{
				"nested": map[string]interface{}{
					"value": 123.0,
					"array": []float64{4.4, 5.5},
				},
			},
		},
	}

	for _, f := range factories {
		for _, tt := range tests {
			t.Run(f.name+"/"+tt.name, func(t *testing.T) {
				L := f.new()
				if L == nil {
					t.Fatal("Failed to create Lua state")
				}
				defer L.Close()

				if err := L.PushTable(tt.data); err != nil {
					t.Fatalf("PushTable() error = %v", err)
				}

				got, err := L.ToTable(-1)
				if err != nil {
					t.Fatalf("ToTable() error = %v", err)
				}

				if !tablesEqual(got, tt.data) {
					t.Errorf("table mismatch\ngot = %v\nwant = %v", got, tt.data)
				}
			})
		}
	}
}

func tablesEqual(a, b map[string]interface{}) bool {
	if len(a) != len(b) {
		return false
	}

	for k, v1 := range a {
		v2, ok := b[k]
		if !ok {
			return false
		}

		switch v1 := v1.(type) {
		case map[string]interface{}:
			v2, ok := v2.(map[string]interface{})
			if !ok || !tablesEqual(v1, v2) {
				return false
			}
		case []float64:
			v2, ok := v2.([]float64)
			if !ok || len(v1) != len(v2) {
				return false
			}
			for i := range v1 {
				if math.Abs(v1[i]-v2[i]) > 1e-10 {
					return false
				}
			}
		default:
			if v1 != v2 {
				return false
			}
		}
	}
	return true
}
