package secret

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

// Provider provides TLS configuration from secrets.
type Provider interface {
	GetTLSConfig(ctx context.Context, secretName, namespace string) (*tls.Config, error)
}

// provider manages Kubernetes secrets and TLS certificates.
type provider struct {
	client kubernetes.Interface
}

// NewProvider creates a new secret provider.
func NewProvider() (Provider, error) {
	restConfig, err := rest.InClusterConfig()
	if err != nil {
		return nil, fmt.Errorf("get in-cluster config: %w", err)
	}

	client, err := kubernetes.NewForConfig(restConfig)
	if err != nil {
		return nil, fmt.Errorf("create kubernetes client: %w", err)
	}

	return &provider{
		client: client,
	}, nil
}

// NewProviderWithClient creates a new secret provider with a provided client (for testing).
func NewProviderWithClient(client kubernetes.Interface) Provider {
	return &provider{
		client: client,
	}
}

// GetTLSConfig retrieves TLS configuration for the given secret.
func (p *provider) GetTLSConfig(ctx context.Context, secretName, namespace string) (*tls.Config, error) {
	secret, err := p.client.CoreV1().Secrets(namespace).Get(ctx, secretName, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("get secret %s/%s: %w", namespace, secretName, err)
	}

	return p.parseTLSSecret(secret)
}

func (p *provider) parseTLSSecret(secret *corev1.Secret) (*tls.Config, error) {
	certPEM, ok := secret.Data["tls.crt"]
	if !ok {
		certPEM, ok = secret.Data["cert.pem"]
		if !ok {
			return nil, errors.New("secret missing tls.crt or cert.pem")
		}
	}

	keyPEM, ok := secret.Data["tls.key"]
	if !ok {
		keyPEM, ok = secret.Data["key.pem"]
		if !ok {
			return nil, errors.New("secret missing tls.key or key.pem")
		}
	}

	cert, err := tls.X509KeyPair(certPEM, keyPEM)
	if err != nil {
		return nil, fmt.Errorf("parse key pair: %w", err)
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		MinVersion:   tls.VersionTLS12,
	}

	// Add CA if present
	if caPEM, ok := secret.Data["ca.crt"]; ok {
		caPool := x509.NewCertPool()
		if !caPool.AppendCertsFromPEM(caPEM) {
			return nil, errors.New("failed to parse CA certificate")
		}
		tlsConfig.RootCAs = caPool
	}

	return tlsConfig, nil
}
