package main

import (
	"net/http"
	"testing"

	"github.com/FernandoVideira/LK_API_Temp/internal/store"
	"github.com/FernandoVideira/LK_API_Temp/internal/store/cache"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

func TestGetUser(t *testing.T) {
	withReddis := config{
		redisCfg: redisConfig{
			enabled: true,
		},
	}

	api := newTestApi(t, withReddis)
	mux := api.mount()

	testToken, err := api.authenticator.GenerateToken(nil)
	if err != nil {
		t.Fatal(err)
	}

	t.Run("should not allow unauthenticated requests", func(t *testing.T) {

		mockStore := api.store.Users.(*store.MockUserStore)
		mockStore.On("GetByID", int64(1)).Return(nil, nil)

		req, err := http.NewRequest(http.MethodGet, "/v1/users/1", nil)
		if err != nil {
			t.Fatal(err)
		}

		rr := executeRequest(req, mux)

		assert.Equal(t, http.StatusUnauthorized, rr.Code, "should not allow unauthenticated requests")

		mockStore.AssertNotCalled(t, "GetByID")

		mockStore.Calls = nil // Reset the mock calls
	})

	t.Run("should allow authenticated requests", func(t *testing.T) {
		mockCacheStore := api.cacheStore.Users.(*cache.MockUserStore)
		mockStore := api.store.Users.(*store.MockUserStore)

		mockCacheStore.On("Get", int64(1)).Return(nil, nil)
		mockCacheStore.On("Set", mock.Anything, mock.Anything).Return(nil)

		mockStore.On("GetByID", int64(1)).Return(&store.User{ID: 1}, nil)
		mockStore.On("GetByID", int64(42)).Return(nil, store.ErrNotFound)

		req, err := http.NewRequest(http.MethodGet, "/v1/users/1", nil)
		if err != nil {
			t.Fatal(err)
		}

		req.Header.Set("Authorization", "Bearer "+testToken)
		rr := executeRequest(req, mux)

		assert.Equal(t, http.StatusOK, rr.Code, "should allow authenticated requests")

		mockStore.AssertNumberOfCalls(t, "GetByID", 2)

		mockCacheStore.Calls = nil // Reset the mock calls
	})

	t.Run("should hit the cache first and if not found add to cache", func(t *testing.T) {
		mockCacheStore := api.cacheStore.Users.(*cache.MockUserStore)

		mockCacheStore.On("Get", int64(42)).Return(nil, nil)
		mockCacheStore.On("Get", int64(1)).Return(nil, nil)
		mockCacheStore.On("Set", mock.Anything, mock.Anything).Return(nil)

		req, err := http.NewRequest(http.MethodGet, "/v1/users/1", nil)
		if err != nil {
			t.Fatal(err)
		}

		req.Header.Set("Authorization", "Bearer "+testToken)
		rr := executeRequest(req, mux)

		assert.Equal(t, http.StatusOK, rr.Code, "should hit the cache first and if not found add to cache")

		mockCacheStore.AssertNumberOfCalls(t, "Get", 2)

		mockCacheStore.Calls = nil // Reset the mock calls
	})

	t.Run("should not hit the cache if it is turned off", func(t *testing.T) {
		withReddis := config{
			redisCfg: redisConfig{
				enabled: false,
			},
		}

		api := newTestApi(t, withReddis)
		mux := api.mount()

		testToken, err := api.authenticator.GenerateToken(nil)
		if err != nil {
			t.Fatal(err)
		}

		mockCacheStore := api.cacheStore.Users.(*cache.MockUserStore)
		mockStore := api.store.Users.(*store.MockUserStore)

		mockStore.On("GetByID", int64(1)).Return(nil, nil)

		req, err := http.NewRequest(http.MethodGet, "/v1/users/1", nil)
		if err != nil {
			t.Fatal(err)
		}

		req.Header.Set("Authorization", "Bearer "+testToken)
		rr := executeRequest(req, mux)

		assert.Equal(t, http.StatusOK, rr.Code, "should not hit the cache if it is turned off")

		mockCacheStore.AssertNotCalled(t, "Get")

		mockCacheStore.Calls = nil // Reset the mock calls
	})
}
