package tsourse

import (
	"context"
	"fmt"

	getsvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/get"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/util"
	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
	objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
	oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
)

// Source represents wrapper over the object service that
// allows checking if a tombstone is available in FrostFS
// network.
//
// Must be created via NewSource function. `var` and `Source{}`
// declarations leads to undefined behaviour and may lead
// to panics.
type Source struct {
	s *getsvc.Service
}

// TombstoneSourcePrm groups required parameters for Source creation.
type TombstoneSourcePrm struct {
	s *getsvc.Service
}

// SetGetService sets object service.
func (s *TombstoneSourcePrm) SetGetService(v *getsvc.Service) {
	s.s = v
}

// NewSource creates, initialize and returns local tombstone Source.
// The returned structure is ready to use.
//
// Panics if any of the provided options does not allow
// constructing a valid tombstone local Source.
func NewSource(p TombstoneSourcePrm) Source {
	if p.s == nil {
		panic("Tombstone source: nil object service")
	}

	return Source(p)
}

type headerWriter struct {
	o *objectSDK.Object
}

func (h *headerWriter) WriteHeader(_ context.Context, o *objectSDK.Object) error {
	h.o = o
	return nil
}

// Tombstone checks if the engine stores tombstone.
// Returns nil, nil if the tombstone has been removed
// or marked for removal.
func (s Source) Tombstone(ctx context.Context, a oid.Address, _ uint64) (*objectSDK.Object, error) {
	var hr headerWriter

	var headPrm getsvc.HeadPrm
	headPrm.WithAddress(a)
	headPrm.SetHeaderWriter(&hr)
	headPrm.SetCommonParameters(&util.CommonPrm{}) // default values are ok for that operation

	err := s.s.Head(ctx, headPrm)
	switch {
	case client.IsErrObjectNotFound(err) || client.IsErrObjectAlreadyRemoved(err):
		return nil, nil
	case err != nil:
		return nil, fmt.Errorf("could not get tombstone from the source: %w", err)
	default:
	}

	if hr.o.Type() != objectSDK.TypeTombstone {
		return nil, fmt.Errorf("returned %s object is not a tombstone", a)
	}

	return hr.o, nil
}