package busauth

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"os"
)

// LoadCATLSConfig builds a *tls.Config that trusts ONLY the given CA certificate
// (PEM file), for a bus client pinning the project's self-signed CA. Because the
// bus uses a private CA rather than a public one, clients must pin it explicitly;
// trusting the system roots would reject the server cert. This is the single
// helper every client (Go peers, the mobile binding, the gateway) uses to turn a
// ca.crt path into a connection config.
func LoadCATLSConfig(caPEMPath string) (*tls.Config, error) {
	pem, err := os.ReadFile(caPEMPath)
	if err != nil {
		return nil, fmt.Errorf("busauth: read CA %q: %w", caPEMPath, err)
	}
	pool := x509.NewCertPool()
	if !pool.AppendCertsFromPEM(pem) {
		return nil, fmt.Errorf("busauth: CA %q contains no valid PEM certificate", caPEMPath)
	}
	return &tls.Config{RootCAs: pool, MinVersion: tls.VersionTLS12}, nil
}

// ServerTLSConfig loads the bus NATS server's certificate and private key (PEM
// files) into a *tls.Config to present to clients. The private key never leaves
// the host; only the CA cert travels to clients.
func ServerTLSConfig(certPEMPath, keyPEMPath string) (*tls.Config, error) {
	cert, err := tls.LoadX509KeyPair(certPEMPath, keyPEMPath)
	if err != nil {
		return nil, fmt.Errorf("busauth: load server keypair: %w", err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}, MinVersion: tls.VersionTLS12}, nil
}

// RouteTLSConfig builds the mutual-TLS config for the NATS CLUSTER route layer
// (issue 0003a). Unlike the client data plane, where the server presents a cert
// and only the client verifies it, routes are server-to-server: each node both
// presents its own node certificate AND verifies the connecting node's
// certificate against the bus CA. So this single config carries:
//
//   - Certificates: this node's CA-signed certificate (presented in both the
//     server and the client role of a route handshake),
//   - RootCAs: the bus CA, to verify the certificate of a node we dial out to,
//   - ClientCAs + ClientAuth=RequireAndVerifyClientCert: the bus CA, to verify
//     the certificate of a node dialing in.
//
// The effect: a node that lacks a certificate signed by the bus CA cannot
// establish a route in either direction, even if it knows the cluster password.
// Reuse the same CA as the client data plane (deploy/tls) but a per-node cert
// whose SAN covers that node's route address.
func RouteTLSConfig(certPEMPath, keyPEMPath, caPEMPath string) (*tls.Config, error) {
	cert, err := tls.LoadX509KeyPair(certPEMPath, keyPEMPath)
	if err != nil {
		return nil, fmt.Errorf("busauth: load route keypair: %w", err)
	}
	pem, err := os.ReadFile(caPEMPath)
	if err != nil {
		return nil, fmt.Errorf("busauth: read route CA %q: %w", caPEMPath, err)
	}
	pool := x509.NewCertPool()
	if !pool.AppendCertsFromPEM(pem) {
		return nil, fmt.Errorf("busauth: route CA %q contains no valid PEM certificate", caPEMPath)
	}
	return &tls.Config{
		Certificates: []tls.Certificate{cert},
		RootCAs:      pool,
		ClientCAs:    pool,
		ClientAuth:   tls.RequireAndVerifyClientCert,
		MinVersion:   tls.VersionTLS12,
	}, nil
}
