package matrix

import (
	"encoding/json"
	"testing"
)

func TestMatchesMetadataFilter_NoFilter_KeepsAll(t *testing.T) {
	meta := json.RawMessage(`{"role":"Forklift Operator","state":"IL"}`)
	if !matchesMetadataFilter(meta, nil) {
		t.Error("nil filter should match everything")
	}
	if !matchesMetadataFilter(meta, map[string]any{}) {
		t.Error("empty filter should match everything")
	}
}

func TestMatchesMetadataFilter_NoMetadata_AlwaysFails(t *testing.T) {
	if matchesMetadataFilter(nil, map[string]any{"x": "y"}) {
		t.Error("missing metadata should fail any filter")
	}
}

func TestMatchesMetadataFilter_SingleValueExactMatch(t *testing.T) {
	meta := json.RawMessage(`{"state":"IL","status":"active","years":5}`)
	cases := []struct {
		filter map[string]any
		want   bool
	}{
		{map[string]any{"state": "IL"}, true},
		{map[string]any{"state": "TX"}, false},
		{map[string]any{"status": "active"}, true},
		{map[string]any{"status": "inactive"}, false},
		// JSON normalizes both sides, so 5 matches 5.0
		{map[string]any{"years": 5.0}, true},
		{map[string]any{"years": 5}, true},
		// Missing key = fail
		{map[string]any{"city": "Chicago"}, false},
	}
	for _, c := range cases {
		got := matchesMetadataFilter(meta, c.filter)
		if got != c.want {
			t.Errorf("filter %v on %s: want %v, got %v", c.filter, meta, c.want, got)
		}
	}
}

func TestMatchesMetadataFilter_AllKeysAND(t *testing.T) {
	meta := json.RawMessage(`{"state":"IL","status":"active","role":"Forklift Operator"}`)
	if !matchesMetadataFilter(meta, map[string]any{
		"state":  "IL",
		"status": "active",
	}) {
		t.Error("both keys match: should pass")
	}
	if matchesMetadataFilter(meta, map[string]any{
		"state":  "IL",
		"status": "inactive", // mismatch
	}) {
		t.Error("one key mismatches: should fail (AND across keys)")
	}
}

func TestMatchesMetadataFilter_ListValueOR(t *testing.T) {
	meta := json.RawMessage(`{"state":"IL"}`)
	// state in {"IL","WI","IN"} → match
	if !matchesMetadataFilter(meta, map[string]any{
		"state": []any{"IL", "WI", "IN"},
	}) {
		t.Error("list with matching element: should pass")
	}
	// state in {"TX","CA"} → fail
	if matchesMetadataFilter(meta, map[string]any{
		"state": []any{"TX", "CA"},
	}) {
		t.Error("list with no matching element: should fail")
	}
}

func TestMatchesMetadataFilter_BoolMatch(t *testing.T) {
	meta := json.RawMessage(`{"available":true,"placed":false}`)
	if !matchesMetadataFilter(meta, map[string]any{"available": true}) {
		t.Error("bool true match")
	}
	if matchesMetadataFilter(meta, map[string]any{"available": false}) {
		t.Error("bool true should not match false filter")
	}
}

func TestMatchesMetadataFilter_MalformedMetadataFails(t *testing.T) {
	meta := json.RawMessage(`{not valid json}`)
	if matchesMetadataFilter(meta, map[string]any{"x": "y"}) {
		t.Error("malformed metadata should fail")
	}
}
