package auth

import (
	"testing"
	"time"

	"code.secondbit.org/uuid"
)

var authCodeStores = []authorizationCodeStore{NewMemstore()}

func compareAuthorizationCodes(authCode1, authCode2 AuthorizationCode) (success bool, field string, authCode1val, authCode2val interface{}) {
	if authCode1.Code != authCode2.Code {
		return false, "code", authCode1.Code, authCode2.Code
	}
	if !authCode1.Created.Equal(authCode2.Created) {
		return false, "created", authCode1.Created, authCode2.Created
	}
	if authCode1.ExpiresIn != authCode2.ExpiresIn {
		return false, "expires in", authCode1.ExpiresIn, authCode2.ExpiresIn
	}
	if !authCode1.ClientID.Equal(authCode2.ClientID) {
		return false, "client ID", authCode1.ClientID, authCode2.ClientID
	}
	if authCode1.Scope != authCode2.Scope {
		return false, "scope", authCode1.Scope, authCode2.Scope
	}
	if authCode1.RedirectURI != authCode2.RedirectURI {
		return false, "redirect URI", authCode1.RedirectURI, authCode2.RedirectURI
	}
	if authCode1.State != authCode2.State {
		return false, "state", authCode1.State, authCode2.State
	}
	return true, "", nil, nil
}

func TestAuthorizationCodeStoreSuccess(t *testing.T) {
	t.Parallel()
	authCode := AuthorizationCode{
		Code:        "code",
		Created:     time.Now(),
		ExpiresIn:   180,
		ClientID:    uuid.NewID(),
		Scope:       "scope",
		RedirectURI: "redirectURI",
		State:       "state",
	}
	for _, store := range authCodeStores {
		err := store.saveAuthorizationCode(authCode)
		if err != nil {
			t.Errorf("Error saving auth code to %T: %s", store, err)
		}
		err = store.saveAuthorizationCode(authCode)
		if err != ErrAuthorizationCodeAlreadyExists {
			t.Errorf("Expected ErrAuthorizationCodeAlreadyExists from %T, got %+v", store, err)
		}
		retrieved, err := store.getAuthorizationCode(authCode.Code)
		if err != nil {
			t.Errorf("Error retrieving auth code from %T: %s", store, err)
		}
		match, field, expectation, result := compareAuthorizationCodes(authCode, retrieved)
		if !match {
			t.Errorf("Expected `%v` in the `%s` field of auth code retrieved from %T, got `%v`", expectation, field, store, result)
		}
		err = store.deleteAuthorizationCode(authCode.Code)
		if err != nil {
			t.Errorf("Error removing auth code from %T: %s", store, err)
		}
		retrieved, err = store.getAuthorizationCode(authCode.Code)
		if err != ErrAuthorizationCodeNotFound {
			t.Errorf("Expected ErrAuthorizationCodeNotFound from %T, got %+v and %+v", store, retrieved, err)
		}
		err = store.deleteAuthorizationCode(authCode.Code)
		if err != ErrAuthorizationCodeNotFound {
			t.Errorf("Expected ErrAuthorizationCodeNotFound from %T, got %+v", store, err)
		}
	}
}
