package store

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

func TestSanitizeJSONForStorageReplacesBinaryWithoutMutatingInput(t *testing.T) {
	payload := []byte("shared binary payload")
	encoded := base64.StdEncoding.EncodeToString(payload)
	input := map[string]any{
		"data": []any{
			map[string]any{"b64_json": encoded},
		},
		"buffer": map[string]any{
			"type": "Buffer",
			"data": []any{float64(1), float64(2), float64(3)},
		},
		"text": "ordinary text",
	}

	report := sanitizeJSONForStorageWithReport(input)
	if report.BinaryCount != 2 {
		t.Fatalf("binary count = %d, want 2", report.BinaryCount)
	}
	next := report.Value.(map[string]any)
	data := next["data"].([]any)
	placeholder := data[0].(map[string]any)["b64_json"].(string)
	if !strings.HasPrefix(placeholder, storagePlaceholderPrefix) {
		t.Fatalf("unexpected placeholder: %q", placeholder)
	}
	if len(placeholder) > 200 {
		t.Fatalf("placeholder exceeds 200 bytes: %d", len(placeholder))
	}
	if !strings.Contains(placeholder, ";prefix="+encoded[:16]+";") {
		t.Fatalf("placeholder should retain the bounded Base64 prefix: %q", placeholder)
	}
	if got := input["data"].([]any)[0].(map[string]any)["b64_json"]; got != encoded {
		t.Fatalf("sanitizer mutated input: %v", got)
	}
	if next["text"] != "ordinary text" {
		t.Fatalf("ordinary text changed: %+v", next)
	}
}

func TestSanitizeJSONForStorageUsesDecodedBytesForEquivalentRepresentations(t *testing.T) {
	payload := []byte("equivalent payload")
	encoded := base64.StdEncoding.EncodeToString(payload)
	report := sanitizeJSONForStorageWithReport(map[string]any{
		"rawBase64": encoded,
		"dataURL":   "data:image/png;base64," + encoded,
		"bytes":     []any{float64('e'), float64('q'), float64('u'), float64('i'), float64('v'), float64('a'), float64('l'), float64('e'), float64('n'), float64('t'), float64(' '), float64('p'), float64('a'), float64('y'), float64('l'), float64('o'), float64('a'), float64('d')},
	})
	if report.BinaryCount != 3 {
		t.Fatalf("binary count = %d, want 3", report.BinaryCount)
	}
	next := report.Value.(map[string]any)
	hashes := map[string]struct{}{}
	for _, key := range []string{"rawBase64", "dataURL", "bytes"} {
		value := next[key].(string)
		hashStart := strings.Index(value, ";sha256=")
		hashEnd := strings.Index(value[hashStart+1:], ";bytes=")
		if hashStart < 0 || hashEnd < 0 {
			t.Fatalf("missing hash in %s placeholder: %q", key, value)
		}
		hashes[value[hashStart+8:hashStart+1+hashEnd]] = struct{}{}
	}
	if len(hashes) != 1 {
		t.Fatalf("equivalent binary values produced different hashes: %+v", next)
	}
}

func TestSanitizeJSONForStorageAvoidsShortGenericTextFalsePositive(t *testing.T) {
	input := map[string]any{"message": "YWJjZA==", "count": json.Number("12")}
	report := sanitizeJSONForStorageWithReport(input)
	if report.BinaryCount != 0 {
		t.Fatalf("short generic Base64-like text should not be sanitized: %+v", report)
	}
}

func TestSanitizeJSONForStorageRecognizesExistingPlaceholder(t *testing.T) {
	value := storageBinaryPlaceholder([]byte("payload"), "image/png", "raw")
	report := sanitizeJSONForStorageWithReport(map[string]any{"b64_json": value})
	if report.BinaryCount != 0 {
		t.Fatalf("existing placeholder should pass the final guard: %+v", report)
	}
}

func TestStorageBinaryPlaceholderIsAlwaysBounded(t *testing.T) {
	value := storageBinaryPlaceholder(
		[]byte("payload"),
		"application/vnd.a-very-long-provider-specific-generated-binary-result+json",
		"data-uri",
	)
	if len(value) > 200 {
		t.Fatalf("placeholder exceeds 200 bytes: %d %q", len(value), value)
	}
	if !strings.Contains(value, ";mime=application/octet-stream;") {
		t.Fatalf("oversized MIME should use the bounded fallback: %q", value)
	}
}
