package macaroons

import (
	"bytes"
	"fmt"

	"golang.org/x/net/context"
	"gopkg.in/macaroon-bakery.v2/bakery"
	"gopkg.in/macaroon.v2"
)

// inMemoryRootKeyStore is a simple implementation of bakery.RootKeyStore that
// stores a single root key in memory.
type inMemoryRootKeyStore struct {
	rootKey []byte
}

// A compile-time check to ensure that inMemoryRootKeyStore implements
// bakery.RootKeyStore.
var _ bakery.RootKeyStore = (*inMemoryRootKeyStore)(nil)

// Get returns the root key for the given id. If the item is not there, it
// returns ErrNotFound.
func (s *inMemoryRootKeyStore) Get(_ context.Context, id []byte) ([]byte,
	error) {

	if !bytes.Equal(id, DefaultRootKeyID) {
		return nil, bakery.ErrNotFound
	}

	return s.rootKey, nil
}

// RootKey returns the root key to be used for making a new macaroon, and an id
// that can be used to look it up later with the Get method.
func (s *inMemoryRootKeyStore) RootKey(context.Context) ([]byte, []byte,
	error) {

	return s.rootKey, DefaultRootKeyID, nil
}

// BakeFromRootKey creates a new macaroon that is derived from the given root
// key and permissions.
func BakeFromRootKey(rootKey []byte,
	permissions []bakery.Op) (*macaroon.Macaroon, error) {

	if len(rootKey) != RootKeyLen {
		return nil, fmt.Errorf("root key must be %d bytes, is %d",
			RootKeyLen, len(rootKey))
	}

	rootKeyStore := &inMemoryRootKeyStore{
		rootKey: rootKey,
	}

	service, err := NewService(rootKeyStore, "lnd", false)
	if err != nil {
		return nil, fmt.Errorf("unable to create service: %w", err)
	}

	ctx := context.Background()
	mac, err := service.NewMacaroon(ctx, DefaultRootKeyID, permissions...)
	if err != nil {
		return nil, fmt.Errorf("unable to create macaroon: %w", err)
	}

	return mac.M(), nil
}