package auth

import (
	"fmt"

	"github.com/gin-gonic/gin"

	"armature/store"
)

// MTLSProxyConfig holds configuration for the proxy-terminated mTLS provider.
type MTLSProxyConfig struct {
	HeaderDN          string // header carrying cert DN (default "X-SSL-Client-DN")
	HeaderVerify      string // header carrying verify status (default "X-SSL-Client-Verify")
	HeaderFingerprint string // header carrying cert fingerprint (default "X-SSL-Client-Fingerprint")
	AutoActivate      bool   // auto-activate new users (default true)
	DefaultTeam       string // team ID for auto-provisioned users (optional)
}

// MTLSProxyProvider authenticates via client certificate headers injected
// by the TLS-terminating reverse proxy (nginx, Traefik, Istio).
//
// The backend never sees the actual TLS handshake — it trusts headers
// injected by the proxy after cert validation. After reading and parsing
// the DN, the provider resolves an existing user or auto-provisions a
// new one, then returns a Result. The auth handler issues an internal JWT.
//
// Header flow:
//
//	Client cert → nginx ssl_verify_client → injects X-SSL-Client-DN,
//	X-SSL-Client-Verify, X-SSL-Client-Fingerprint → backend reads headers.
type MTLSProxyProvider struct {
	cfg MTLSProxyConfig
}

func NewMTLSProxyProvider(cfg MTLSProxyConfig) *MTLSProxyProvider {
	if cfg.HeaderDN == "" {
		cfg.HeaderDN = "X-SSL-Client-DN"
	}
	if cfg.HeaderVerify == "" {
		cfg.HeaderVerify = "X-SSL-Client-Verify"
	}
	if cfg.HeaderFingerprint == "" {
		cfg.HeaderFingerprint = "X-SSL-Client-Fingerprint"
	}
	return &MTLSProxyProvider{cfg: cfg}
}

func (p *MTLSProxyProvider) Mode() Mode { return ModeMTLS }

func (p *MTLSProxyProvider) SupportsRegistration() bool { return false }

func (p *MTLSProxyProvider) Register(_ *gin.Context, _ store.Stores) (*Result, error) {
	return nil, ErrNotSupported
}

// Authenticate reads the cert DN and verify status from proxy headers,
// parses the DN fields, and resolves or auto-provisions the user.
//
// Returns ErrInvalidCreds when headers are missing or verify fails.
// Returns ErrInactive when user exists but is deactivated.
func (p *MTLSProxyProvider) Authenticate(c *gin.Context, stores store.Stores) (*Result, error) {
	// ── Validate headers ───────────────────────────────────────────
	verify := c.GetHeader(p.cfg.HeaderVerify)
	if verify == "" {
		return nil, fmt.Errorf("%w: missing %s header", ErrInvalidCreds, p.cfg.HeaderVerify)
	}
	// nginx: "SUCCESS", Traefik: "0" (both mean valid cert)
	if verify != "SUCCESS" && verify != "0" {
		return nil, fmt.Errorf("%w: cert verify=%s", ErrInvalidCreds, verify)
	}

	dn := c.GetHeader(p.cfg.HeaderDN)
	if dn == "" {
		return nil, fmt.Errorf("%w: missing %s header", ErrInvalidCreds, p.cfg.HeaderDN)
	}

	fields := ParseDN(dn)
	cn := fields["CN"]
	if cn == "" {
		return nil, fmt.Errorf("%w: cert DN has no CN field", ErrInvalidCreds)
	}

	// Stable external identity: fingerprint if available, else full DN
	fingerprint := c.GetHeader(p.cfg.HeaderFingerprint)
	if fingerprint == "" {
		fingerprint = dn
	}

	return resolveOrProvision(
		c.Request.Context(), stores, cn, fields, fingerprint,
		p.cfg.AutoActivate, p.cfg.DefaultTeam,
	)
}
