package auth

import (
	"testing"
	"time"

	"code.secondbit.org/uuid"
)

var grantStores = []grantStore{NewMemstore()}

func compareGrants(grant1, grant2 Grant) (success bool, field string, grant1val, grant2val interface{}) {
	if grant1.Code != grant2.Code {
		return false, "code", grant1.Code, grant2.Code
	}
	if !grant1.Created.Equal(grant2.Created) {
		return false, "created", grant1.Created, grant2.Created
	}
	if grant1.ExpiresIn != grant2.ExpiresIn {
		return false, "expires in", grant1.ExpiresIn, grant2.ExpiresIn
	}
	if !grant1.ClientID.Equal(grant2.ClientID) {
		return false, "client ID", grant1.ClientID, grant2.ClientID
	}
	if grant1.Scope != grant2.Scope {
		return false, "scope", grant1.Scope, grant2.Scope
	}
	if grant1.RedirectURI != grant2.RedirectURI {
		return false, "redirect URI", grant1.RedirectURI, grant2.RedirectURI
	}
	if grant1.State != grant2.State {
		return false, "state", grant1.State, grant2.State
	}
	return true, "", nil, nil
}

func TestGrantStoreSuccess(t *testing.T) {
	t.Parallel()
	grant := Grant{
		Code:        "code",
		Created:     time.Now(),
		ExpiresIn:   180,
		ClientID:    uuid.NewID(),
		Scope:       "scope",
		RedirectURI: "redirectURI",
		State:       "state",
	}
	for _, store := range grantStores {
		err := store.saveGrant(grant)
		if err != nil {
			t.Errorf("Error saving grant to %T: %s", store, err)
		}
		err = store.saveGrant(grant)
		if err != ErrGrantAlreadyExists {
			t.Errorf("Expected ErrGrantAlreadyExists from %T, got %+v", store, err)
		}
		retrieved, err := store.getGrant(grant.Code)
		if err != nil {
			t.Errorf("Error retrieving grant from %T: %s", store, err)
		}
		match, field, expectation, result := compareGrants(grant, retrieved)
		if !match {
			t.Errorf("Expected `%v` in the `%s` field of grant retrieved from %T, got `%v`", expectation, field, store, result)
		}
		err = store.deleteGrant(grant.Code)
		if err != nil {
			t.Errorf("Error removing grant from %T: %s", store, err)
		}
		retrieved, err = store.getGrant(grant.Code)
		if err != ErrGrantNotFound {
			t.Errorf("Expected ErrGrantNotFound from %T, got %+v and %+v", store, retrieved, err)
		}
		err = store.deleteGrant(grant.Code)
		if err != ErrGrantNotFound {
			t.Errorf("Expected ErrGrantNotFound from %T, got %+v", store, err)
		}
	}
}
