package database

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

// Storage is the parent interface for the database backends of route.
type Storage interface {
	// routes
	GetRoute(ctx context.Context, host string) (Route, error)
	GetAllRoutes(ctx context.Context, user string) ([]Route, error)
	PutRoute(ctx context.Context, domain, kind string) (Route, error)
	DeleteRoute(ctx context.Context, id string) error

	// tokens
	GetToken(ctx context.Context, token string) (Token, error)
	GetTokenID(ctx context.Context, id string) (Token, error)
	GetTokensForOwner(ctx context.Context, owner string) ([]Token, error)
	PutToken(ctx context.Context, token, owner string, scopes []string) (Token, error)
	DeleteToken(ctx context.Context, id string) error
	DeactivateToken(ctx context.Context, id string) error

	// certificates
	GetCert(ctx context.Context, key string) ([]byte, error)
	PutCert(ctx context.Context, key string, data []byte) error
	DeleteCert(ctx context.Context, key string) error

	Close() error
}

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,
	})
}