// Copyright (c) 2026 Sidero Labs, Inc.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.

// Package k8sproxy provides JWT-authenticated proxy to Kubernetes API server.
package k8sproxy

import (
	"context"
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
	"go.uber.org/zap"
	"k8s.io/client-go/rest"

	"github.com/siderolabs/omni/client/api/common"
	"github.com/siderolabs/omni/internal/backend/runtime/kubernetes"
)

// clusterContextKey is a type for cluster name.
type clusterContextKey struct{ ClusterName string }

// Handler implements the HTTP reverse proxy for Kubernetes clusters.
//
// Handler intercepts the request, verifies the authentication info and
// routes the request to matching Kubernetes cluster with impersonation headers.
//
// Handler itself implements httt.Handler interface.
type Handler struct {
	multiplexer *multiplexer
	chain       http.Handler
}

// MiddlewareWrapper is an interface for middleware wrappers.
type MiddlewareWrapper interface {
	Wrap(http.Handler) http.Handler
}

// KubernetesRuntime provides kubernetes proxy capabilities.
type KubernetesRuntime interface {
	RegisterCleanuper(kubernetes.ClusterCleanuper)
	GetKubeconfig(ctx context.Context, cluster *common.Context) (*rest.Config, error)
}

// NewHandler creates a new Handler.
func NewHandler(keyFunc KeyProvider, clusterUUIDResolver ClusterUUIDResolver, wrapper MiddlewareWrapper, logger *zap.Logger, k8sRuntime KubernetesRuntime) (*Handler, error) {
	multiplexer := newMultiplexer(k8sRuntime)
	proxy := wrapper.Wrap(newProxyHandler(multiplexer, logger))

	handler := &Handler{
		multiplexer: multiplexer,
		chain:       AuthorizeRequest(proxy, keyFunc, clusterUUIDResolver),
	}

	k8sRuntime.RegisterCleanuper(handler)

	return handler, nil
}

// ServeHTTP implements http.Handler interface.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.chain.ServeHTTP(w, r)
}

// ClusterRemove implements ClusterCleanuper interface.
func (h *Handler) ClusterRemove(clusterName string) {
	h.multiplexer.removeClusterConnector(clusterName)
}

// Describe implements prom.Collector interface.
func (h *Handler) Describe(ch chan<- *prometheus.Desc) {
	h.multiplexer.Describe(ch)
}

// Collect implements prom.Collector interface.
func (h *Handler) Collect(ch chan<- prometheus.Metric) {
	h.multiplexer.Collect(ch)
}

var _ prometheus.Collector = &Handler{}
