package mtls

import (
	"crypto/tls"
	"crypto/x509"
	"sync/atomic"
)

// CertHolder enables zero-downtime cert rotation: the TLS config reads
// the current cert via an atomic pointer, so a rotation agent can swap it
// for new handshakes without disturbing existing connections — the same
// atomic-swap pattern as gw-03 route reload and gw-04 membership.
type CertHolder struct {
	cur atomic.Pointer[tls.Certificate]
}

func NewCertHolder(initial tls.Certificate) *CertHolder {
	h := &CertHolder{}
	h.cur.Store(&initial)
	return h
}

// Set installs a new server certificate; new handshakes pick it up.
func (h *CertHolder) Set(c tls.Certificate) { h.cur.Store(&c) }

// get is the tls.Config.GetCertificate callback.
func (h *CertHolder) get(*tls.ClientHelloInfo) (*tls.Certificate, error) {
	return h.cur.Load(), nil
}

// Current returns the active certificate (for tests/observability).
func (h *CertHolder) Current() *tls.Certificate { return h.cur.Load() }

// ServerTLSConfig builds a mutual-TLS server config: TLS 1.3, a
// hot-rotating server cert, and REQUIRED + verified client certs chained
// to clientCAs. ALPN advertises h2 then http/1.1.
func ServerTLSConfig(h *CertHolder, clientCAs *x509.CertPool) *tls.Config {
	return &tls.Config{
		MinVersion:     tls.VersionTLS13,
		GetCertificate: h.get,
		ClientAuth:     tls.RequireAndVerifyClientCert, // mTLS: demand a verified client cert
		ClientCAs:      clientCAs,
		NextProtos:     []string{"h2", "http/1.1"},
	}
}

// ClientTLSConfig builds a client config that presents `cert` and trusts
// `roots` (for tests and the gateway's origin-side mTLS).
func ClientTLSConfig(cert tls.Certificate, roots *x509.CertPool) *tls.Config {
	return &tls.Config{
		MinVersion:   tls.VersionTLS13,
		Certificates: []tls.Certificate{cert},
		RootCAs:      roots,
	}
}
