package br

import (
	"context"
	"strconv"

	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/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

type RestoreAdapter interface {
	PrepareRestore(ctx context.Context, req *globalngv1.RestoreClusterRequest) (submitRestore, bizerr.BizError)
	GetRestoreRunningStatus(ctx context.Context, clusterId uint64, restore *entity.Restore) (*globalngv1.RestoreStatusResponse, bizerr.BizError)
	StopRestore(ctx context.Context, req *globalngv1.StopRestoreClusterRequest) bizerr.BizError
}

type submitRestore func(context.Context) bizerr.BizError

func (s *serviceImpl) isManualBackup(ctx context.Context, backupId uint64) (bool, bizerr.BizError) {
	backup, berr := s.backupRepo.Get(ctx, backupId)
	if berr != nil {
		return false, berr.Chain("failed to get backup")
	}
	if backup != nil && backup.TriggerType == schema.BackupTriggerTypeManual {
		return true, nil
	}
	return false, nil
}

func (s *serviceImpl) getRestoreAdapter(
	ctx context.Context,
	createReq *globalngv1.RestoreClusterRequest,
	restoreEntity *entity.Restore,
) (RestoreAdapter, bizerr.BizError) {
	if createReq != nil {
		switch createReq.GetRestoreMode() {
		case globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT, globalngv1.RestoreMode_RESTORE_MODE_PITR:
			if createReq.GetRestoreMode() == globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT && createReq.GetBackupId() != "" {
				backupId, err := strconv.ParseUint(createReq.GetBackupId(), 10, 64)
				if err != nil {
					return nil, bizerr.WrapError(err, "failed to parse backup id")
				}
				isManual, berr := s.isManualBackup(ctx, backupId)
				if berr != nil {
					return nil, berr
				}
				if isManual {
					return s.restoreAdapterManual, nil
				}
			}
			return s.restoreAdapterPremium, nil
		case globalngv1.RestoreMode_RESTORE_MODE_DEDICATED_SNAPSHOT:
			return s.restoreAdapterDedicated, nil
		case globalngv1.RestoreMode_RESTORE_MODE_CLASSIC_SNAPSHOT:
			return s.restoreAdapterClassic, nil
		default:
			return nil, bizerr.New(bizerr.ErrCodeParams, "invalid restore mode in create request")
		}
	}

	if restoreEntity != nil {
		switch restoreEntity.RestoreMode {
		case schema.RestoreModeSnapshot, schema.RestoreModePitr:
			if restoreEntity.RestoreMode == schema.RestoreModeSnapshot {
				isManual, berr := s.isManualBackup(ctx, restoreEntity.BackupId)
				if berr != nil {
					return nil, berr
				}
				if isManual {
					return s.restoreAdapterManual, nil
				}
			}
			return s.restoreAdapterPremium, nil
		case schema.RestoreModeDedicatedSnapshot:
			return s.restoreAdapterDedicated, nil
		case schema.RestoreModeClassicSnapshot:
			return s.restoreAdapterClassic, nil
		default:
			return nil, bizerr.New(bizerr.ErrCodeParams, "invalid restore mode in restore entity")
		}
	}

	return nil, bizerr.New(bizerr.GeneralInternalErrorCode, "get restore adapter failed")
}
