package service

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/serverless-service/internal/config"
	"github.com/tidbcloud/serverless-service/internal/domain/constant"
	"github.com/tidbcloud/serverless-service/internal/domain/entity"
	"github.com/tidbcloud/serverless-service/internal/domain/repo/mock_repo"
	"github.com/tidbcloud/serverless-service/internal/errorcode"
	"go.uber.org/mock/gomock"
)

func TestExportServiceExceedConcurrencyLimit(t *testing.T) {
	const tenantID = "1001"

	tests := []struct {
		name      string
		limit     int64
		running   int
		listErr   bizerr.BizError
		wantCode  bizerr.ErrCode
		wantError bool
	}{
		{
			name:    "allows exports below configured limit",
			limit:   2,
			running: 1,
		},
		{
			name:      "rejects exports at configured limit",
			limit:     2,
			running:   2,
			wantCode:  errorcode.ErrCodeExportConcurrencyLimitExceeded,
			wantError: true,
		},
		{
			name:      "propagates list errors",
			limit:     2,
			listErr:   bizerr.New(bizerr.ErrCodeDB, "list exports"),
			wantError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			originalConfig := config.Global()
			config.Set(&config.CentralConfig{BizConfig: config.BizConfig{
				MaxExportConcurrencyPerOrg: tt.limit,
			}})
			t.Cleanup(func() { config.Set(originalConfig) })

			ctrl := gomock.NewController(t)
			exportRepo := mock_repo.NewMockExportRepo(ctrl)
			runningExports := make([]*entity.Export, tt.running)
			exportRepo.EXPECT().ListByFilter(gomock.Any(), entity.ExportFilter{
				TenantID: tenantID,
				States: []constant.ExportState{
					constant.ExportStatePreparing,
					constant.ExportStateRunning,
				},
			}).Return(runningExports, tt.listErr)

			svc := &exportService{exportRepo: exportRepo}
			err := svc.exceedConcurrencyLimit(context.Background(), tenantID)
			if !tt.wantError {
				require.NoError(t, err)
				return
			}
			require.Error(t, err)
			if tt.listErr != nil {
				require.Same(t, tt.listErr, err)
				return
			}
			require.Equal(t, tt.wantCode, err.ErrCode())
		})
	}
}
