package runtimeworker

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

type workOwnershipVerifier interface {
	VerifyActive(context.Context) error
}

// ownershipController keeps process health bound to the durable worker
// authority even when the work queue is empty. Durable effects remain fenced
// by their family transaction; this guard owns only the process-level promise
// that a Ready worker still holds the configured authority tuple.
type ownershipController struct {
	authority  workOwnershipVerifier
	controller func(context.Context) error
	interval   time.Duration
	ready      atomic.Bool
	checks     authorityCheckObservation
}

func newOwnershipController(authority workOwnershipVerifier, controller func(context.Context) error, interval time.Duration) (*ownershipController, error) {
	if authority == nil || controller == nil || interval <= 0 {
		return nil, errors.New("runtime worker: ownership controller configuration is incomplete")
	}
	return &ownershipController{authority: authority, controller: controller, interval: interval}, nil
}

func (c *ownershipController) Ready() bool {
	return c != nil && c.ready.Load()
}

func (c *ownershipController) snapshot() authorityCheckSnapshot {
	if c == nil {
		return authorityCheckSnapshot{}
	}
	return c.checks.snapshot()
}

func (c *ownershipController) verify(ctx context.Context) error {
	started := time.Now()
	err := c.authority.VerifyActive(ctx)
	c.checks.observe(started, err == nil)
	return err
}

func (c *ownershipController) Run(ctx context.Context) error {
	if c == nil || c.authority == nil || c.controller == nil || c.interval <= 0 {
		return errors.New("runtime worker: ownership controller is unavailable")
	}
	if err := c.verify(ctx); err != nil {
		return err
	}

	controllerCtx, cancel := context.WithCancel(ctx)
	defer cancel()
	controllerDone := make(chan error, 1)
	c.ready.Store(true)
	defer c.ready.Store(false)
	go func() {
		controllerDone <- c.controller(controllerCtx)
	}()

	ticker := time.NewTicker(c.interval)
	defer ticker.Stop()
	for {
		select {
		case err := <-controllerDone:
			return err
		case <-ctx.Done():
			cancel()
			<-controllerDone
			return nil
		case <-ticker.C:
			if err := c.verify(ctx); err != nil {
				// Fail readiness before waiting for the family controller to
				// observe cancellation. Its transactional fence remains the
				// final authority for any in-flight durable effect.
				c.ready.Store(false)
				cancel()
				<-controllerDone
				return err
			}
		}
	}
}
