package millproto

import (
	"bytes"
	"encoding/binary"
	"testing"

	millv1 "tangled.org/core/spindle/mill/proto/gen"
)

func TestEncodeDecodeRoundTrip(t *testing.T) {
	var buf bytes.Buffer
	enc := NewEncoder(&buf)

	want := &Message{
		ReserveSeat: &millv1.ReserveSeat{
			LeaseId:         "lease-1",
			TargetEngine:    "microvm",
			RawWorkflowJson: `{"name":"build"}`,
			Knot:            "knot.example",
			Rkey:            "abc123",
			TtlSeconds:      30,
		},
	}
	if err := enc.Encode(want); err != nil {
		t.Fatalf("Encode() error = %v", err)
	}

	got, err := NewDecoder(&buf).Decode()
	if err != nil {
		t.Fatalf("Decode() error = %v", err)
	}
	rs := got.GetReserveSeat()
	if rs == nil {
		t.Fatal("decoded message missing reserve_seat")
	}
	if rs.LeaseId != "lease-1" || rs.TargetEngine != "microvm" || rs.TtlSeconds != 30 {
		t.Fatalf("round-trip mismatch: %+v", rs)
	}
}

func TestDecoderRejectsOversizedMessage(t *testing.T) {
	var tooLarge bytes.Buffer
	var header [4]byte
	binary.BigEndian.PutUint32(header[:], MaxMessageBytes+1)
	tooLarge.Write(header[:])

	if _, err := NewDecoder(&tooLarge).Decode(); err == nil {
		t.Fatal("expected oversized message error")
	}
}

func TestValidationOneofRequired(t *testing.T) {
	// exactly one payload set: ok
	if err := validator.Validate(&Message{Ack: &millv1.Ack{UpToOffset: 5}}); err != nil {
		t.Fatalf("expected valid message to pass, got: %v", err)
	}
	// zero payloads: fail
	if err := validator.Validate(&Message{}); err == nil {
		t.Fatal("expected message with zero payloads to fail validation")
	}
	// two payloads: fail
	if err := validator.Validate(&Message{
		Ack:       &millv1.Ack{},
		Committed: &millv1.Committed{LeaseId: "x"},
	}); err == nil {
		t.Fatal("expected message with multiple payloads to fail validation")
	}
}
