package br

import (
	"context"
	"time"

	"github.com/tidbcloud/pkgv2/db"
	"go.opentelemetry.io/otel"

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

var backupPolicyTracer = otel.Tracer("backup_policy_repo_impl")

type backupPolicyRepoImpl struct {
	provider db.Provider
}

func NewBackupPolicyRepo(provider db.Provider) br.BackupPolicyRepo {
	return &backupPolicyRepoImpl{
		provider: provider,
	}
}

func (r *backupPolicyRepoImpl) Save(ctx context.Context, backupPolicy *entity.BackupPolicy) bizerr.BizError {
	ctx, span := backupPolicyTracer.Start(ctx, "backupPolicyRepo.Save")
	defer span.End()

	if backupPolicy == nil {
		return bizerr.New(bizerr.ErrCodeUnknown, "backup policy entity is nil")
	}

	wdb := r.provider.WriteDB(ctx)
	schemaBackupPolicy := backupPolicy.BackupPolicy
	schemaBackupPolicy.UpdatedAt = time.Now()

	if err := wdb.Save(schemaBackupPolicy).Error; err != nil {
		return bizerr.WrapGormError(err, "failed to save backup policy")
	}

	return nil
}

func (r *backupPolicyRepoImpl) Get(ctx context.Context, name schema.BackupPolicyName) (*entity.BackupPolicy, bizerr.BizError) {
	ctx, span := backupPolicyTracer.Start(ctx, "backupPolicyRepo.Get")
	defer span.End()

	// Validate name is not empty
	if name == "" {
		return nil, bizerr.New(bizerr.ErrCodeParams, "backup policy name cannot be empty")
	}

	rdb := r.provider.ReadDB(ctx)
	var schemaBackupPolicy schema.BackupPolicy
	if err := rdb.Where("name = ?", name).First(&schemaBackupPolicy).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "failed to get backup policy")
	}

	return &entity.BackupPolicy{BackupPolicy: &schemaBackupPolicy}, nil
}

func (r *backupPolicyRepoImpl) ListAll(ctx context.Context) ([]*entity.BackupPolicy, bizerr.BizError) {
	ctx, span := backupPolicyTracer.Start(ctx, "backupPolicyRepo.ListAll")
	defer span.End()

	rdb := r.provider.ReadDB(ctx)
	var schemaBackupPolicies []*schema.BackupPolicy
	if err := rdb.Find(&schemaBackupPolicies).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "failed to list all backup policies")
	}

	backupPolicies := make([]*entity.BackupPolicy, len(schemaBackupPolicies))
	for i, schemaBackupPolicy := range schemaBackupPolicies {
		backupPolicies[i] = &entity.BackupPolicy{BackupPolicy: schemaBackupPolicy}
	}

	return backupPolicies, nil
}
