package br

import (
	"testing"

	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/br/mock_br"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func TestOverrideFlexibleBackupRetentionValidation(t *testing.T) {
	tests := []struct {
		name    string
		req     *globalngv1.OverrideFlexibleBackupRetentionRequest
		errText string
	}{
		{name: "nil request", errText: "reason is required"},
		{
			name:    "blank reason",
			req:     &globalngv1.OverrideFlexibleBackupRetentionRequest{ClusterId: "1", RetentionDays: 1, Reason: "  "},
			errText: "reason is required",
		},
		{
			name:    "negative retention",
			req:     &globalngv1.OverrideFlexibleBackupRetentionRequest{ClusterId: "1", RetentionDays: -1, Reason: "incident"},
			errText: "between 1 and 33",
		},
		{
			name:    "zero retention",
			req:     &globalngv1.OverrideFlexibleBackupRetentionRequest{ClusterId: "1", RetentionDays: 0, Reason: "incident"},
			errText: "between 1 and 33",
		},
		{
			name:    "retention too large",
			req:     &globalngv1.OverrideFlexibleBackupRetentionRequest{ClusterId: "1", RetentionDays: 34, Reason: "incident"},
			errText: "between 1 and 33",
		},
		{
			name:    "invalid cluster id",
			req:     &globalngv1.OverrideFlexibleBackupRetentionRequest{ClusterId: "invalid", RetentionDays: 1, Reason: "incident"},
			errText: "cluster_id is invalid",
		},
	}

	service := &serviceImpl{}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_, err := service.OverrideFlexibleBackupRetention(t.Context(), tt.req)
			require.Error(t, err)
			require.ErrorContains(t, err, tt.errText)
		})
	}
}

func TestOverrideFlexibleBackupRetentionRejectsStandardBundle(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	settingRepo := mock_br.NewMockBackupSettingRepo(ctrl)
	settingRepo.EXPECT().Get(gomock.Any(), uint64(1)).Return(&entity.BackupSetting{BackupSetting: &schema.BackupSetting{
		ClusterId: 1, Mode: schema.BackupModeStandardBundle,
	}}, nil)
	service := &serviceImpl{backupSettingRepo: settingRepo}

	_, err := service.OverrideFlexibleBackupRetention(t.Context(), &globalngv1.OverrideFlexibleBackupRetentionRequest{
		ClusterId: "1", RetentionDays: 33, Reason: "incident mitigation",
	})

	require.Error(t, err)
	require.ErrorContains(t, err, "only supported for flexible retention")
}

func TestOverrideFlexibleBackupRetentionReturnsSettingRepoError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	settingRepo := mock_br.NewMockBackupSettingRepo(ctrl)
	expectedErr := bizerr.New(bizerr.ErrCodeDB, "load failed")
	settingRepo.EXPECT().Get(gomock.Any(), uint64(1)).Return(nil, expectedErr)
	service := &serviceImpl{backupSettingRepo: settingRepo}

	_, err := service.OverrideFlexibleBackupRetention(t.Context(), &globalngv1.OverrideFlexibleBackupRetentionRequest{
		ClusterId: "1", RetentionDays: 1, Reason: "incident mitigation",
	})

	require.ErrorIs(t, err, expectedErr)
}
