package impl

import (
	"context"
	"time"

	"github.com/tidbcloud/dataflow-service/app/repo"
	"github.com/tidbcloud/dataflow-service/app/repo/entity"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/pkgv2/db"
	"gorm.io/gorm/clause"
)

type classicRestoreAccessRepoImpl struct {
	dbProvider db.Provider
}

var _ repo.ClassicRestoreAccessRepo = (*classicRestoreAccessRepoImpl)(nil)

func NewClassicRestoreAccessRepo(dbProvider db.Provider) repo.ClassicRestoreAccessRepo {
	return &classicRestoreAccessRepoImpl{dbProvider: dbProvider}
}

func (r *classicRestoreAccessRepoImpl) GetOrCreate(
	ctx context.Context, access *entity.ClassicRestoreAccess,
) (*entity.ClassicRestoreAccess, bizerr.BizError) {
	db := r.dbProvider.WriteDB(ctx)
	if err := db.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "restore_id"}, {Name: "bucket_id"}},
		DoNothing: true,
	}).Create(access).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "create classic restore access")
	}
	existing := &entity.ClassicRestoreAccess{}
	if err := db.Where("restore_id = ? AND bucket_id = ?", access.RestoreID, access.BucketID).
		First(existing).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "get existing classic restore access")
	}
	return existing, nil
}

func (r *classicRestoreAccessRepoImpl) Get(
	ctx context.Context, restoreID string, bucketID uint64,
) (*entity.ClassicRestoreAccess, bizerr.BizError) {
	access := &entity.ClassicRestoreAccess{}
	result := r.dbProvider.WriteDB(ctx).
		Where("restore_id = ? AND bucket_id = ?", restoreID, bucketID).
		Find(access)
	if result.Error != nil {
		return nil, bizerr.WrapGormError(result.Error, "get classic restore access")
	}
	if result.RowsAffected == 0 {
		return nil, nil
	}
	return access, nil
}

func (r *classicRestoreAccessRepoImpl) ListExpired(
	ctx context.Context, now time.Time,
) ([]entity.ClassicRestoreAccess, bizerr.BizError) {
	var accesses []entity.ClassicRestoreAccess
	if err := r.dbProvider.ReadDB(ctx).Where("expires_at <= ?", now).Find(&accesses).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "list expired classic restore accesses")
	}
	return accesses, nil
}

func (r *classicRestoreAccessRepoImpl) Delete(ctx context.Context, id entity.ID) bizerr.BizError {
	if err := r.dbProvider.WriteDB(ctx).Delete(&entity.ClassicRestoreAccess{}, id).Error; err != nil {
		return bizerr.WrapGormError(err, "delete classic restore access %d", id)
	}
	return nil
}
