package runtimeworker

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

	"github.com/nexuscrm/persistence"
)

type ownershipVerifierProbe struct {
	mu    sync.Mutex
	calls int
	lost  chan struct{}
}

func (p *ownershipVerifierProbe) VerifyActive(context.Context) error {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.calls++
	select {
	case <-p.lost:
		return persistence.ErrRuntimeWorkOwnershipLost
	default:
		return nil
	}
}

func (p *ownershipVerifierProbe) callCount() int {
	p.mu.Lock()
	defer p.mu.Unlock()
	return p.calls
}

func TestOwnershipControllerLosesReadinessWithoutWork(t *testing.T) {
	verifier := &ownershipVerifierProbe{lost: make(chan struct{})}
	controllerStarted := make(chan struct{})
	guard, err := newOwnershipController(verifier, func(ctx context.Context) error {
		close(controllerStarted)
		<-ctx.Done()
		return nil
	}, time.Millisecond)
	if err != nil {
		t.Fatal(err)
	}
	done := make(chan error, 1)
	go func() { done <- guard.Run(context.Background()) }()
	select {
	case <-controllerStarted:
	case <-time.After(time.Second):
		t.Fatal("family controller did not start")
	}
	if !guard.Ready() {
		t.Fatal("ownership controller is not ready after initial verification")
	}
	close(verifier.lost)
	select {
	case err := <-done:
		if !errors.Is(err, persistence.ErrRuntimeWorkOwnershipLost) {
			t.Fatalf("Run() = %v", err)
		}
	case <-time.After(time.Second):
		t.Fatal("ownership controller did not stop after authority loss")
	}
	if guard.Ready() {
		t.Fatal("ownership controller remained ready after authority loss")
	}
	if verifier.callCount() < 2 {
		t.Fatalf("VerifyActive calls = %d, want startup and periodic checks", verifier.callCount())
	}
	snapshot := guard.snapshot()
	if snapshot.Checks < 2 || snapshot.Failures != 1 || snapshot.LastSuccess.IsZero() {
		t.Fatalf("ownership observation = %+v, want startup success and authority-loss failure", snapshot)
	}
}

func TestOwnershipControllerRejectsIncompleteConfiguration(t *testing.T) {
	verifier := &ownershipVerifierProbe{lost: make(chan struct{})}
	controller := func(context.Context) error { return nil }
	for name, tc := range map[string]struct {
		authority workOwnershipVerifier
		run       func(context.Context) error
		interval  time.Duration
	}{
		"authority":  {run: controller, interval: time.Second},
		"controller": {authority: verifier, interval: time.Second},
		"interval":   {authority: verifier, run: controller},
	} {
		t.Run(name, func(t *testing.T) {
			if _, err := newOwnershipController(tc.authority, tc.run, tc.interval); err == nil {
				t.Fatal("newOwnershipController() succeeded")
			}
		})
	}
}
