package pkcs15

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/x509"
)

// pkcs15KeyCert holds the data for a key and certificate pair; it provides
// various methods to transform pkcs15 data
type pkcs15KeyCert struct {
	key  crypto.PrivateKey
	cert *x509.Certificate
	// store the encrypted enveloped Private Key for re-use
	envelopedPrivateKey []byte
}

// KeyType is used by consumers to check for compatibility
type KeyType int

const (
	KeyTypeRSA1024 KeyType = iota
	KeyTypeRSA2048
	KeyTypeRSA3072
	KeyTypeRSA4096

	KeyTypeECP256
	KeyTypeECP384
	KeyTypeECP521

	KeyTypeUnknown
)

// KeyType returns the private key type
func (p15 *pkcs15KeyCert) KeyType() KeyType {
	switch pKey := p15.key.(type) {
	case *rsa.PrivateKey:
		switch pKey.N.BitLen() {
		case 1024:
			return KeyTypeRSA1024
		case 2048:
			return KeyTypeRSA2048
		case 3072:
			return KeyTypeRSA3072
		case 4096:
			return KeyTypeRSA4096

		default:
		}

	case *ecdsa.PrivateKey:
		switch pKey.Curve.Params().Name {
		case "P-256":
			return KeyTypeECP256
		case "P-384":
			return KeyTypeECP384
		case "P-521":
			return KeyTypeECP521

		default:
		}

	default:
	}

	return KeyTypeUnknown
}

// ParsePEMToPKCS15 parses the provide pem files to a pkcs15 struct; it also does some
// basic sanity check; if any of this fails, an error is returned
func ParsePEMToPKCS15(keyPem, certPem []byte) (*pkcs15KeyCert, error) {
	// decode / check key
	key, err := pemKeyDecode(keyPem)
	if err != nil {
		return nil, err
	}

	// decode / check cert
	cert, err := pemCertDecode(certPem, keyPem)
	if err != nil {
		return nil, err
	}

	// create p15 struct
	p15 := &pkcs15KeyCert{
		key:  key,
		cert: cert,
	}

	// pre-calculate encrypted envelope
	err = p15.computeEncryptedKeyEnvelope()
	if err != nil {
		return nil, err
	}

	return p15, nil
}