package getsvc

import (
	"context"
	"io"

	objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
)

// ChunkWriter is an interface of target component
// to write payload chunk.
type ChunkWriter interface {
	WriteChunk(context.Context, []byte) error
}

// HeaderWriter is an interface of target component
// to write object header.
type HeaderWriter interface {
	WriteHeader(context.Context, *objectSDK.Object) error
}

// ObjectWriter is an interface of target component to write object.
type ObjectWriter interface {
	HeaderWriter
	ChunkWriter
}

type SimpleObjectWriter struct {
	obj *objectSDK.Object

	pld []byte
}

type partWriter struct {
	ObjectWriter

	headWriter HeaderWriter

	chunkWriter ChunkWriter
}

type hasherWrapper struct {
	hash io.Writer
}

func NewSimpleObjectWriter() *SimpleObjectWriter {
	return &SimpleObjectWriter{
		obj: objectSDK.New(),
	}
}

func (s *SimpleObjectWriter) WriteHeader(_ context.Context, obj *objectSDK.Object) error {
	s.obj = obj
	s.pld = make([]byte, 0, obj.PayloadSize())
	return nil
}

func (s *SimpleObjectWriter) WriteChunk(_ context.Context, p []byte) error {
	s.pld = append(s.pld, p...)
	return nil
}

func (s *SimpleObjectWriter) Object() *objectSDK.Object {
	if len(s.pld) > 0 {
		s.obj.SetPayload(s.pld)
	}

	return s.obj
}

func (w *partWriter) WriteChunk(ctx context.Context, p []byte) error {
	return w.chunkWriter.WriteChunk(ctx, p)
}

func (w *partWriter) WriteHeader(ctx context.Context, o *objectSDK.Object) error {
	return w.headWriter.WriteHeader(ctx, o)
}

func (h *hasherWrapper) WriteChunk(_ context.Context, p []byte) error {
	_, err := h.hash.Write(p)
	return err
}

type payloadWriter struct {
	origin ChunkWriter
	obj    *objectSDK.Object
}

func (w *payloadWriter) WriteChunk(ctx context.Context, p []byte) error {
	return w.origin.WriteChunk(ctx, p)
}

func (w *payloadWriter) WriteHeader(_ context.Context, o *objectSDK.Object) error {
	w.obj = o
	return nil
}