package usecase

import (
	"context"
	"errors"
	"math"
	"testing"

	"backend/pkg/member/domain/entity"
	mockRepo "backend/pkg/member/mock/repository"

	GIDLib "code.30cm.net/digimon/library-go/utils/invited_code"
	"github.com/stretchr/testify/assert"
	"go.uber.org/mock/gomock"
)

func TestMemberUseCase_Generate(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	mockAutoIDRepository := mockRepo.NewMockAutoIDRepository(mockCtrl)

	uc := MustMemberUseCase(MemberUseCaseParam{
		GenerateUID: mockAutoIDRepository,
	})

	tests := []struct {
		name      string
		mockSetup func()
		wantErr   bool
		expected  string
	}{
		{
			name: "successful UID generation",
			mockSetup: func() {
				mockAutoIDRepository.EXPECT().Inc(gomock.Any(), gomock.Any()).DoAndReturn(
					func(ctx context.Context, data *entity.AutoID) error {
						data.Counter = 123
						return nil
					},
				)
				mockAutoIDRepository.EXPECT().GetUIDFromNum(int64(GIDLib.InitAutoID+123)).Return("generatedUID", nil)
			},
			wantErr:  false,
			expected: "generatedUID",
		},
		{
			name: "increment error",
			mockSetup: func() {
				mockAutoIDRepository.EXPECT().Inc(gomock.Any(), gomock.Any()).Return(errors.New("increment error"))
			},
			wantErr: true,
		},
		{
			name: "UID generation error",
			mockSetup: func() {
				mockAutoIDRepository.EXPECT().Inc(gomock.Any(), gomock.Any()).DoAndReturn(
					func(ctx context.Context, data *entity.AutoID) error {
						data.Counter = 123
						return nil
					},
				)
				mockAutoIDRepository.EXPECT().GetUIDFromNum(int64(GIDLib.InitAutoID+123)).Return("", errors.New("UID generation error"))
			},
			wantErr: true,
		},
		{
			name: "sum exceeds int64",
			mockSetup: func() {
				mockAutoIDRepository.EXPECT().Inc(gomock.Any(), gomock.Any()).DoAndReturn(
					func(ctx context.Context, data *entity.AutoID) error {
						data.Counter = math.MaxInt64 // Force overflow
						return nil
					},
				)
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.mockSetup()
			result, err := uc.Generate(context.Background())

			if tt.wantErr {
				assert.Error(t, err)
				assert.Empty(t, result)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.expected, result)
			}
		})
	}
}
