package report

import (
	"io"
	"log"
	"testing"
)

type fakeClaimSettings struct {
	hash    string
	gen     int
	issued  string
	setCall int
}

func (f *fakeClaimSettings) GetClaimCode() (string, int, string) { return f.hash, f.gen, f.issued }
func (f *fakeClaimSettings) SetClaimCode(hash string, gen int, issued string) error {
	f.hash, f.gen, f.issued = hash, gen, issued
	f.setCall++
	return nil
}

func newSync(f *fakeClaimSettings) *ClaimSync {
	return &ClaimSync{Settings: f, Logger: log.New(io.Discard, "", 0)}
}

// A newer generation caches; the same/older generation and nil are no-ops (idempotent, one-way).
func TestClaimSync_IdempotentByGeneration(t *testing.T) {
	f := &fakeClaimSettings{}
	s := newSync(f)

	s.Reconcile(&ClaimStatus{CodeHash: "h1", Generation: 1, IssuedAt: "t1"})
	if f.gen != 1 || f.hash != "h1" || f.setCall != 1 {
		t.Fatalf("first cache: %+v", f)
	}

	// Same generation → no write.
	s.Reconcile(&ClaimStatus{CodeHash: "h1-again", Generation: 1, IssuedAt: "t1"})
	if f.setCall != 1 || f.hash != "h1" {
		t.Fatalf("same generation must not rewrite: %+v", f)
	}

	// Older generation → no write (a lagging ACK can't regress the cache).
	s.Reconcile(&ClaimStatus{CodeHash: "h0", Generation: 0, IssuedAt: "t0"})
	if f.setCall != 1 {
		t.Fatalf("older generation must not rewrite: %+v", f)
	}

	// Newer generation (a resend) → cache advances.
	s.Reconcile(&ClaimStatus{CodeHash: "h2", Generation: 2, IssuedAt: "t2"})
	if f.gen != 2 || f.hash != "h2" || f.setCall != 2 {
		t.Fatalf("newer generation should advance: %+v", f)
	}

	// nil / empty / non-positive generation → no-op (old hub, no claim row).
	s.Reconcile(nil)
	s.Reconcile(&ClaimStatus{CodeHash: "", Generation: 3})
	s.Reconcile(&ClaimStatus{CodeHash: "h", Generation: 0})
	if f.setCall != 2 {
		t.Fatalf("nil/empty/zero-gen must be no-ops: %+v", f)
	}
}
