package wal

import (
	"strings"
	"testing"

	"github.com/dailz/go-kv/config"
)

func makeEntry(opType uint8, valueKind uint8, keySize, valSize int) *WalEntry {
	key := make([]byte, keySize)
	for i := range key {
		key[i] = byte('a' + i%26)
	}
	val := make([]byte, valSize)
	for i := range val {
		val[i] = byte('x')
	}
	return &WalEntry{OpType: opType, ValueKind: valueKind, Key: key, Value: val}
}

func TestValidateBatchLimitsPass(t *testing.T) {
	cfg := config.Defaults()
	entries := make([]*WalEntry, 100)
	for i := range entries {
		entries[i] = makeEntry(OpPut, VKInline, 10, 10)
	}
	if err := ValidateBatchLimits(entries, &cfg); err != nil {
		t.Fatalf("expected nil error, got: %v", err)
	}
}

func TestValidateEntryCountExceeded(t *testing.T) {
	cfg := config.Defaults()
	entries := make([]*WalEntry, 10001)
	for i := range entries {
		entries[i] = makeEntry(OpPut, VKInline, 10, 10)
	}
	err := ValidateBatchLimits(entries, &cfg)
	if err == nil {
		t.Fatal("expected error for entry count exceeded")
	}
	if !strings.Contains(err.Error(), "entry count") {
		t.Fatalf("expected error containing 'entry count', got: %v", err)
	}
}

func TestValidateKeyTooBig(t *testing.T) {
	cfg := config.Defaults()
	// 5KB key exceeds 4KB limit
	entries := []*WalEntry{makeEntry(OpPut, VKInline, 5*1024, 10)}
	err := ValidateBatchLimits(entries, &cfg)
	if err == nil {
		t.Fatal("expected error for key too big")
	}
	if !strings.Contains(err.Error(), "key") {
		t.Fatalf("expected error containing 'key', got: %v", err)
	}
}

func TestValidateValueTooBig(t *testing.T) {
	cfg := config.Defaults()
	// 5KB inline value exceeds 4KB limit
	entries := []*WalEntry{makeEntry(OpPut, VKInline, 10, 5*1024)}
	err := ValidateBatchLimits(entries, &cfg)
	if err == nil {
		t.Fatal("expected error for value too big")
	}
	if !strings.Contains(err.Error(), "value") {
		t.Fatalf("expected error containing 'value', got: %v", err)
	}
}

func TestValidateEmptyBatch(t *testing.T) {
	cfg := config.Defaults()
	err := ValidateBatchLimits(nil, &cfg)
	if err == nil {
		t.Fatal("expected error for empty batch")
	}
	if !strings.Contains(err.Error(), "entry count") && !strings.Contains(err.Error(), "> 0") {
		t.Fatalf("expected error about empty batch, got: %v", err)
	}

	err = ValidateBatchLimits([]*WalEntry{}, &cfg)
	if err == nil {
		t.Fatal("expected error for empty batch")
	}
}

func TestValidateTotalSizeExceeded(t *testing.T) {
	cfg := config.Defaults()
	// Create entries that collectively exceed MaxBatchSize (4MB).
	// Each entry with 1000-byte key + 1000-byte value ≈ 2012 bytes encoded.
	// 2100 entries × ~2012 ≈ ~4.2MB > 4MB
	entries := make([]*WalEntry, 2100)
	for i := range entries {
		entries[i] = makeEntry(OpPut, VKInline, 1000, 1000)
	}
	err := ValidateBatchLimits(entries, &cfg)
	if err == nil {
		t.Fatal("expected error for total size exceeded")
	}
	if !strings.Contains(err.Error(), "batch size") {
		t.Fatalf("expected error containing 'batch size', got: %v", err)
	}
}
