package scrape

import (
	"context"
	"errors"
	"sync/atomic"
	"testing"
	"time"

	"github.com/rs/zerolog"
)

type fakeReconciler struct {
	name  string
	calls atomic.Int32
	fail  bool
}

func (f *fakeReconciler) Name() string { return f.name }
func (f *fakeReconciler) Reconcile(ctx context.Context) error {
	f.calls.Add(1)
	if f.fail {
		return errors.New("synthetic")
	}
	return nil
}

func TestReconcileLoopRunsOnInterval(t *testing.T) {
	r := &fakeReconciler{name: "x"}
	l := NewReconcileLoop(80*time.Millisecond, zerolog.Nop())
	l.Add(r)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	l.Start(ctx)
	defer l.Stop()
	time.Sleep(250 * time.Millisecond)
	calls := r.calls.Load()
	if calls < 2 {
		t.Errorf("expected ≥2 calls, got %d", calls)
	}
}

func TestReconcileLoopHandlesFailures(t *testing.T) {
	r1 := &fakeReconciler{name: "ok"}
	r2 := &fakeReconciler{name: "bad", fail: true}
	l := NewReconcileLoop(50*time.Millisecond, zerolog.Nop())
	l.Add(r1)
	l.Add(r2)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	l.Start(ctx)
	defer l.Stop()
	time.Sleep(180 * time.Millisecond)
	if r1.calls.Load() < 2 || r2.calls.Load() < 2 {
		t.Errorf("both reconcilers should keep running; got r1=%d r2=%d",
			r1.calls.Load(), r2.calls.Load())
	}
}

func TestReconcileLoopStopsCleanly(t *testing.T) {
	r := &fakeReconciler{name: "x"}
	l := NewReconcileLoop(40*time.Millisecond, zerolog.Nop())
	l.Add(r)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	l.Start(ctx)
	time.Sleep(120 * time.Millisecond)
	l.Stop()
	stoppedAt := r.calls.Load()
	time.Sleep(120 * time.Millisecond)
	if r.calls.Load() != stoppedAt {
		t.Errorf("Reconcile kept running after Stop: %d → %d",
			stoppedAt, r.calls.Load())
	}
}
