package cardissuer

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

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

	issuer := NewLocalIssuer("test-secret-with-enough-length-for-cards")
	card, err := issuer.CreateVirtualCard(t.Context(), CreateVirtualCardParams{Network: "visa"})
	if err != nil {
		t.Fatalf("create card: %v", err)
	}

	if len(card.Sensitive.PAN) != 16 {
		t.Fatalf("expected 16 digit PAN, got %q", card.Sensitive.PAN)
	}
	if !validLuhn(card.Sensitive.PAN) {
		t.Fatalf("expected generated PAN to pass Luhn, got %q", card.Sensitive.PAN)
	}
	if len(card.Sensitive.CVV) != 3 {
		t.Fatalf("expected 3 digit CVV, got %q", card.Sensitive.CVV)
	}
	if card.PANFingerprint == "" || card.ExternalCardID == "" {
		t.Fatal("expected issuer metadata")
	}
}

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

	card := SensitiveCard{
		PAN:      "4111111111111111",
		CVV:      "123",
		ExpMonth: 12,
		ExpYear:  2030,
	}

	defaultJSON, err := json.Marshal(card)
	if err != nil {
		t.Fatalf("marshal sensitive card: %v", err)
	}
	if strings.Contains(string(defaultJSON), "4111111111111111") || strings.Contains(string(defaultJSON), "123") {
		t.Fatalf("default sensitive card JSON leaked PAN/CVV: %s", defaultJSON)
	}

	disclosureJSON, err := json.Marshal(card.OneTimeDisclosure())
	if err != nil {
		t.Fatalf("marshal one-time disclosure: %v", err)
	}
	if !strings.Contains(string(disclosureJSON), "4111111111111111") || !strings.Contains(string(disclosureJSON), "123") {
		t.Fatalf("one-time disclosure should include PAN/CVV: %s", disclosureJSON)
	}
}

func validLuhn(number string) bool {
	sum := 0
	double := false

	for i := len(number) - 1; i >= 0; i-- {
		digit := int(number[i] - '0')
		if double {
			digit *= 2
			if digit > 9 {
				digit -= 9
			}
		}
		sum += digit
		double = !double
	}

	return sum%10 == 0
}
