package aggregation

import (
	"bytes"
	"context"
	"net/http"

	v1 "github.com/rancher/wrangler/v2/pkg/generated/controllers/core/v1"
	"github.com/sirupsen/logrus"
	corev1 "k8s.io/api/core/v1"
)

func Watch(ctx context.Context, controller v1.SecretController, secretNamespace, secretName string, httpHandler http.Handler) {
	if secretNamespace == "" || secretName == "" {
		return
	}
	h := handler{
		ctx:       ctx,
		handler:   httpHandler,
		namespace: secretNamespace,
		name:      secretName,
	}
	controller.OnChange(ctx, "aggregation-controller", h.OnSecret)
}

type handler struct {
	handler         http.Handler
	namespace, name string

	url    string
	caCert []byte
	token  string
	ctx    context.Context
	cancel func()
}

func (h *handler) OnSecret(key string, secret *corev1.Secret) (*corev1.Secret, error) {
	if secret == nil {
		return nil, nil
	}

	if secret.Namespace != h.namespace ||
		secret.Name != h.name {
		return secret, nil
	}

	url, caCert, token, restart, err := h.shouldRestart(secret)
	if err != nil {
		return secret, err
	}
	if !restart {
		return secret, nil
	}

	if h.cancel != nil {
		logrus.Info("Restarting steve aggregation client")
		h.cancel()
	} else {
		logrus.Info("Starting steve aggregation client")
	}

	ctx, cancel := context.WithCancel(h.ctx)
	go ListenAndServe(ctx, url, caCert, token, h.handler)

	h.url = url
	h.caCert = caCert
	h.token = token
	h.cancel = cancel

	return secret, nil
}

func (h *handler) shouldRestart(secret *corev1.Secret) (string, []byte, string, bool, error) {
	url := string(secret.Data["url"])
	if url == "" {
		return "", nil, "", false, nil
	}

	token := string(secret.Data["token"])
	if token == "" {
		return "", nil, "", false, nil
	}

	caCert := secret.Data["ca.crt"]

	if h.url != url ||
		h.token != token ||
		!bytes.Equal(h.caCert, caCert) {
		return url, caCert, token, true, nil
	}

	return "", nil, "", false, nil
}
