package cache

import (
	"context"
	"sync"
	"time"

	"github.com/rancher/lasso/pkg/client"
)

const (
	defaultTimeout = 15 * time.Second
)

type healthcheck struct {
	lock     sync.Mutex
	cf       client.SharedClientFactory
	callback func(bool)
}

func (h *healthcheck) ping(ctx context.Context) bool {
	ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
	defer cancel()
	if h.cf == nil {
		return false
	}
	return h.cf.IsHealthy(ctx)
}

func (h *healthcheck) start(ctx context.Context, cf client.SharedClientFactory) error {
	first, err := h.initialize(cf)
	if err != nil {
		return err
	}
	if first {
		h.ensureHealthy(ctx)
	}
	return nil
}

func (h *healthcheck) initialize(cf client.SharedClientFactory) (bool, error) {
	h.lock.Lock()
	defer h.lock.Unlock()
	if h.cf != nil {
		return false, nil
	}

	h.cf = cf
	return true, nil
}

func (h *healthcheck) ensureHealthy(ctx context.Context) {
	h.lock.Lock()
	defer h.lock.Unlock()
	h.pingUntilGood(ctx)
}

func (h *healthcheck) report(good bool) {
	if h.callback != nil {
		h.callback(good)
	}
}

func (h *healthcheck) pingUntilGood(ctx context.Context) {
	for {
		if h.ping(ctx) {
			h.report(true)
			return
		}

		h.report(false)
		time.Sleep(defaultTimeout)
	}
}
