package carddata

import (
	"encoding/json"
	"strings"
	"testing"
)

func TestRedactJSONRedactsCardData(t *testing.T) {
	t.Parallel()

	raw := []byte(`{
		"id": "evt_123",
		"card_number": "4111111111111111",
		"data": {
			"card": {
				"number": "5555555555554444",
				"cvv": "123",
				"exp_month": 12,
				"exp_year": 2030,
				"last4": "4444"
			},
			"merchant": "Demo Shop",
			"amount_cents": 2500
		},
		"track2": "4111111111111111=30121010000000000000"
	}`)

	redacted := string(RedactJSON(raw))
	for _, forbidden := range []string{"4111111111111111", "5555555555554444", `"123"`, "30121010000000000000"} {
		if strings.Contains(redacted, forbidden) {
			t.Fatalf("expected card data to be redacted from %s", redacted)
		}
	}
	if !strings.Contains(redacted, Redacted) {
		t.Fatalf("expected redaction marker in %s", redacted)
	}

	var decoded map[string]any
	if err := json.Unmarshal([]byte(redacted), &decoded); err != nil {
		t.Fatalf("redacted JSON should remain valid: %v", err)
	}
}

func TestRedactJSONKeepsNonCardNumbers(t *testing.T) {
	t.Parallel()

	redacted := string(RedactJSON([]byte(`{"number":"invoice-42","amount_cents":1200,"sequence_number":"abc"}`)))
	if strings.Contains(redacted, Redacted) {
		t.Fatalf("expected non-card numbers to be preserved, got %s", redacted)
	}
	if !strings.Contains(redacted, "invoice-42") || !strings.Contains(redacted, "sequence_number") {
		t.Fatalf("expected original non-card fields, got %s", redacted)
	}
}

func TestRedactJSONInvalidBodyReturnsEmptyObject(t *testing.T) {
	t.Parallel()

	if got := string(RedactJSON([]byte(`not-json`))); got != `{}` {
		t.Fatalf("expected invalid JSON to be replaced by empty object, got %s", got)
	}
}
