package extsvc

import (
	"errors"
	"testing"
	"time"
)

func TestBreakerLifecycle(t *testing.T) {
	b := NewBreaker()
	now := time.Date(2026, 6, 12, 12, 0, 0, 0, time.UTC)
	b.now = func() time.Time { return now }
	boom := errors.New("boom")

	if b.State() != "closed" || !b.Allow() {
		t.Fatal("fresh breaker must be closed")
	}

	// two failures: still closed
	b.Record(boom)
	b.Record(boom)
	if b.State() != "closed" || !b.Allow() {
		t.Fatal("breaker must stay closed below threshold")
	}

	// third consecutive failure opens it
	b.Record(boom)
	if b.State() != "open" {
		t.Fatalf("state = %s, want open", b.State())
	}
	if b.Allow() {
		t.Fatal("open breaker must reject calls")
	}

	// after the cooldown one probe is allowed (half-open)
	now = now.Add(61 * time.Second)
	if !b.Allow() {
		t.Fatal("half-open must allow one probe")
	}
	if b.Allow() {
		t.Fatal("only one probe may be in flight")
	}
	if b.State() != "half-open" {
		t.Fatalf("state = %s, want half-open", b.State())
	}

	// failed probe re-opens for another cooldown
	b.Record(boom)
	if b.Allow() {
		t.Fatal("failed probe must re-open the breaker")
	}
	now = now.Add(61 * time.Second)
	if !b.Allow() {
		t.Fatal("next probe window")
	}

	// successful probe closes it fully
	b.Record(nil)
	if b.State() != "closed" || !b.Allow() || !b.Allow() {
		t.Fatal("successful probe must close the breaker")
	}
}

func TestBreakerSuccessResetsCount(t *testing.T) {
	b := NewBreaker()
	boom := errors.New("x")
	b.Record(boom)
	b.Record(boom)
	b.Record(nil) // non-consecutive failures never open
	b.Record(boom)
	b.Record(boom)
	if b.State() != "closed" {
		t.Fatal("interleaved success must reset the failure count")
	}
}
