package sender

import (
	"errors"
	"fmt"
	"testing"

	"host-agent/internal/payload"
)

// 전송이 계속 실패하면 페이로드를 보관하되 용량을 넘으면 가장 오래된 것부터 버린다.
func TestBufferCapsAtMaxDroppingOldest(t *testing.T) {
	b := NewBuffer(3)
	fail := func(payload.HostPayload) error { return errors.New("server down") }

	for i := 0; i < 5; i++ {
		b.Push(payload.HostPayload{Hostname: fmt.Sprintf("h%d", i)})
		_ = b.Flush(fail)
	}
	if b.Len() != 3 {
		t.Fatalf("버퍼 크기 3 기대, got %d", b.Len())
	}

	// 서버 복구: 오래된 것부터 순서대로 전부 재전송된다.
	var sent []string
	ok := func(p payload.HostPayload) error {
		sent = append(sent, p.Hostname)
		return nil
	}
	if err := b.Flush(ok); err != nil {
		t.Fatalf("Flush 실패: %v", err)
	}
	if b.Len() != 0 {
		t.Errorf("전송 후 버퍼가 비어야 함, got %d", b.Len())
	}
	want := []string{"h2", "h3", "h4"}
	if len(sent) != len(want) {
		t.Fatalf("전송 %d건 기대, got %d (%v)", len(want), len(sent), sent)
	}
	for i := range want {
		if sent[i] != want[i] {
			t.Errorf("전송 순서[%d]: got %s, want %s", i, sent[i], want[i])
		}
	}
}

// 중간에 다시 실패하면 성공분만 제거하고 나머지는 다음 기회를 위해 보관한다.
func TestBufferPartialFlushKeepsRemainder(t *testing.T) {
	b := NewBuffer(10)
	b.Push(payload.HostPayload{Hostname: "a"})
	b.Push(payload.HostPayload{Hostname: "b"})
	b.Push(payload.HostPayload{Hostname: "c"})

	calls := 0
	flaky := func(p payload.HostPayload) error {
		calls++
		if calls >= 2 { // 첫 건만 성공하고 다시 실패
			return errors.New("down again")
		}
		return nil
	}
	if err := b.Flush(flaky); err == nil {
		t.Error("실패 시 Flush가 에러를 반환해야 함")
	}
	if b.Len() != 2 {
		t.Errorf("실패분 2건 보관 기대, got %d", b.Len())
	}
}
