package v1beta1

import (
	"context"
	"testing"

	"github.com/AlekSi/pointer"
	"github.com/bufbuild/protovalidate-go"
	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/dataflow-service/app/models/domain"
	pb "github.com/tidbcloud/dataflow-service/idl/pbgen/proto/adminapi/v1beta1"
)

func TestModifyBackupSettingsRequest_DailyScheduleValidation(t *testing.T) {
	validator, err := protovalidate.New()
	require.NoError(t, err)

	req := &pb.ModifyBackupSettingsRequest{
		ClusterId: "1",
		SnapshotBackupSchedule: &pb.SnapshotBackupSchedule{
			Enabled: pointer.ToBool(true),
			Schedule: &pb.SnapshotBackupSchedule_DailySchedule{
				DailySchedule: &pb.DailySchedule{
					ScheduleTime: "01:00",
				},
			},
			RetentionDays: pointerToInt32(90),
		},
	}

	require.NoError(t, validator.Validate(req))
}

func TestValidateModifyBackupSettingParams_PITREnabledRequired(t *testing.T) {
	controller := &BackupControllerImpl{}

	err := controller.validateModifyBackupSettingParams(context.Background(), &pb.ModifyBackupSettingsRequest{
		ClusterId:   "1",
		PitrSetting: &pb.PITRSetting{},
	})

	require.Error(t, err)
	require.Contains(t, err.Error(), "pitr_setting.enabled is required")
}

func TestValidateModifyBackupSettingParams_DisabledSnapshotScheduleAllowsSparsePayload(t *testing.T) {
	controller := &BackupControllerImpl{}

	err := controller.validateModifyBackupSettingParams(context.Background(), &pb.ModifyBackupSettingsRequest{
		ClusterId: "1",
		SnapshotBackupSchedule: &pb.SnapshotBackupSchedule{
			Enabled: pointer.ToBool(false),
		},
	})

	require.NoError(t, err)
}

func TestValidateModifyBackupSettingParams_DisabledSnapshotScheduleRejectsInvalidProvidedSchedule(t *testing.T) {
	controller := &BackupControllerImpl{}

	err := controller.validateModifyBackupSettingParams(context.Background(), &pb.ModifyBackupSettingsRequest{
		ClusterId: "1",
		SnapshotBackupSchedule: &pb.SnapshotBackupSchedule{
			Enabled: pointer.ToBool(false),
			Schedule: &pb.SnapshotBackupSchedule_DailySchedule{
				DailySchedule: &pb.DailySchedule{},
			},
		},
	})

	require.Error(t, err)
	require.Contains(t, err.Error(), "daily_schedule.schedule_time is required")
}

func TestResolveSnapshotBackupSchedule_PreservesCurrentValues(t *testing.T) {
	resolved, err := resolveSnapshotBackupSchedule(&pb.SnapshotBackupSchedule{
		RetentionDays: pointerToInt32(14),
	}, &domain.QueryBackupSettingForAPIResp{
		SnapshotBackupSchedule: &domain.SnapshotBackupSchedule{
			Disable:           false,
			ScheduleType:      domain.SnapshotBackupScheduleTypeDaily,
			DailyScheduleTime: "01:00",
			RetentionPolicy: &domain.RetentionPolicy{
				RetentionPeriod: 7,
			},
		},
	})

	require.NoError(t, err)
	require.True(t, resolved.Enabled)
	require.Equal(t, int32(14), resolved.RetentionDays)
	require.Equal(t, domain.SnapshotBackupScheduleTypeDaily, resolved.ScheduleType)
	require.Equal(t, "01:00", resolved.DailyScheduleTime)
}

func TestResolveSnapshotBackupSchedule_EnabledRequiresMergedRetentionAndSchedule(t *testing.T) {
	resolved, err := resolveSnapshotBackupSchedule(&pb.SnapshotBackupSchedule{
		Enabled: pointer.ToBool(true),
	}, nil)

	require.Nil(t, resolved)
	require.Error(t, err)
	require.Contains(t, err.Error(), "retention_days must be greater than 0")
}

func pointerToInt32(v int32) *int32 {
	return &v
}
