package database

import (
	"io"

	"github.com/asdine/storm"
	"golang.org/x/crypto/acme/autocert"
	"golang.org/x/net/context"
)

// Certs is the set of API calls needed to manage certificate resources.
//
// Database backends should implement this interface, they will not need
// to implement certificate decryption, as that will be handled in the layer
// above this DAO.
type Certs interface {
	io.Closer
	autocert.Cache
}

// CryptoLevel indicates what form of cryptography the certificate is stored
// with.
type CryptoLevel int

// Crypto levels / strategies defined
const (
	// NOTE: this is defined for debugging / testing usage only
	CryptoLevelNone CryptoLevel = iota

	// Use the global set of secretbox keys
	CryptoLevelSecretbox
)

// CachedCert is an individual cached certificate in the database.
type CachedCert struct {
	Key         string `storm:"id"`
	CryptoLevel CryptoLevel
	// PEM-encoded bytes with the above crypto level as a filter.
	Body []byte
}

type storageManager struct {
	Storage
}

func (s *storageManager) Get(ctx context.Context, key string) ([]byte, error) {
	data, err := s.GetCert(ctx, key)
	if err != nil {
		if err == storm.ErrNotFound {
			return nil, autocert.ErrCacheMiss
		} else {
			return nil, err
		}
	}

	return data, nil
}

func (s *storageManager) Put(ctx context.Context, key string, data []byte) error {
	return s.PutCert(ctx, key, data)
}

func (s *storageManager) Delete(ctx context.Context, key string) error {
	return s.DeleteCert(ctx, key)
}

// Cache creates an autocert.Cache from a Storage instance.
func Cache(s Storage) autocert.Cache {
	return autocert.Cache(&storageManager{
		Storage: s,
	})
}
