package nebula

import (
	"fmt"
	"reflect"

	"github.com/slackhq/nebula/cert"
)

// Certificate wraps a NebulaCertificate to provide convenient (and consistent)
// text (un)marshaling methods as well as normalization for equality checking.
type Certificate struct {
	inner cert.NebulaCertificate
}

// NewCertificate returns a Certificate wrapping the given one.
func NewCertificate(inner cert.NebulaCertificate) (Certificate, error) {
	// normalize the inner cert by marshaling to and unmarshaling from the PEM.
	// This allows equality checking in tests to work between certs which have
	// never been written to disk and those which have.
	b, err := inner.MarshalToPEM()
	if err != nil {
		return Certificate{}, fmt.Errorf("marshaling to PEM: %w", err)
	}

	normInner, _, err := cert.UnmarshalNebulaCertificateFromPEM(b)
	if err != nil {
		return Certificate{}, fmt.Errorf("unmarshaling from PEM: %w", err)
	}

	return Certificate{inner: *normInner}, nil
}

// Unwrap returns the wrapped NebulaCertificate type.
func (c Certificate) Unwrap() *cert.NebulaCertificate {
	return &c.inner
}

// MarshalText implements the encoding.TextMarshaler interface.
func (c Certificate) MarshalText() ([]byte, error) {
	if reflect.DeepEqual(c, Certificate{}) {
		return []byte(""), nil
	}
	return c.inner.MarshalToPEM()
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (c *Certificate) UnmarshalText(b []byte) error {
	if len(b) == 0 {
		*c = Certificate{}
		return nil
	}

	nebCrt, _, err := cert.UnmarshalNebulaCertificateFromPEM(b)
	if err != nil {
		return fmt.Errorf("unmarshaling nebula certificate from PEM: %w", err)
	}
	c.inner = *nebCrt
	return nil
}