package backup

import (
	"context"
	"errors"

	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/mysql/schema"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repo"
	"github.com/tidbcloud/pkgv2/db"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"
)

type backupGcSettingRepoImp struct {
	provider db.Provider
}

func NewBackupGcSettingRepo(provider db.Provider) repo.BackupGcSettingRepo {
	return &backupGcSettingRepoImp{provider: provider}
}

func (r *backupGcSettingRepoImp) Create(ctx context.Context, backupGcSetting *entity.BackupGcSetting) error {
	return r.provider.WriteDB(ctx).Create(backupGcSetting).Error
}

func (r *backupGcSettingRepoImp) Save(ctx context.Context, backupGcSetting *entity.BackupGcSetting) error {
	ret := r.provider.WriteDB(ctx).Updates(backupGcSetting)
	if ret.Error != nil {
		return ret.Error
	}
	if ret.RowsAffected == 0 {
		return repo.ErrOptimisticLock
	}
	return nil
}

func (r *backupGcSettingRepoImp) Load(ctx context.Context, sharedPoolId string) (*entity.BackupGcSetting, error) {
	rdb := r.provider.ReadDB(ctx)
	var backupGcSettingModel schema.BackupGcSetting
	if err := rdb.Where("shared_pool_id = ?", sharedPoolId).First(&backupGcSettingModel).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Errorf(codes.NotFound, "BackupGcSetting with sharedPoolId %s not found", sharedPoolId)
		}
		return nil, err
	}
	return &entity.BackupGcSetting{BackupGcSetting: backupGcSettingModel}, nil
}

func (r *backupGcSettingRepoImp) Delete(ctx context.Context, sharedPoolId string) error {
	return r.provider.WriteDB(ctx).Where("shared_pool_id = ?", sharedPoolId).Delete(&schema.BackupGcSetting{}).Error
}

func (r *backupGcSettingRepoImp) List(ctx context.Context, filter *repo.BackupGcSettingFilter) ([]*entity.BackupGcSetting, error) {
	rdb := r.provider.ReadDB(ctx)
	if len(filter.IncludeStatuses) > 0 {
		rdb = rdb.Where("status IN ?", filter.IncludeStatuses)
	}
	if filter.HasManualBackup != nil {
		rdb = rdb.Where("has_manual_backup = ?", *filter.HasManualBackup)
	}
	var backupGcSettings []*schema.BackupGcSetting
	if err := rdb.Find(&backupGcSettings).Error; err != nil {
		return nil, err
	}
	var result []*entity.BackupGcSetting
	for _, backupGcSettingModel := range backupGcSettings {
		result = append(result, &entity.BackupGcSetting{BackupGcSetting: *backupGcSettingModel})
	}

	return result, nil
}
