package erasurecode

import (
	"crypto/ecdsa"

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

// Split splits fully formed object into multiple chunks.
func (c *Constructor) Split(obj *objectSDK.Object, key *ecdsa.PrivateKey) ([]*objectSDK.Object, error) {
	c.clear()

	header, err := obj.CutPayload().Marshal()
	if err != nil {
		return nil, err
	}

	headerShards, err := c.encodeRaw(header)
	if err != nil {
		return nil, err
	}
	payloadShards, err := c.encodeRaw(obj.Payload())
	if err != nil {
		return nil, err
	}

	parts := make([]*objectSDK.Object, len(payloadShards))
	parent, _ := obj.ID()
	for i := range parts {
		chunk := objectSDK.New()
		copyRequiredFields(chunk, obj)
		chunk.SetPayload(payloadShards[i])
		chunk.SetPayloadSize(uint64(len(payloadShards[i])))

		var parentSplitParentID *oid.ID
		if obj.HasParent() {
			splitParentID, ok := obj.Parent().ID()
			if ok {
				parentSplitParentID = &splitParentID
			}
		}

		ecParentInfo := objectSDK.ECParentInfo{
			ID:            parent,
			SplitID:       obj.SplitID(),
			SplitParentID: parentSplitParentID,
			Attributes:    obj.Attributes(),
		}

		ec := objectSDK.NewECHeader(ecParentInfo, uint32(i), uint32(len(payloadShards)), headerShards[i], uint32(len(header)))
		chunk.SetECHeader(ec)
		if err := setIDWithSignature(chunk, key); err != nil {
			return nil, err
		}

		parts[i] = chunk
	}
	return parts, nil
}

func setIDWithSignature(obj *objectSDK.Object, key *ecdsa.PrivateKey) error {
	objectSDK.CalculateAndSetPayloadChecksum(obj)

	if err := objectSDK.CalculateAndSetID(obj); err != nil {
		return err
	}

	if key == nil {
		return nil
	}

	return objectSDK.CalculateAndSetSignature(*key, obj)
}

func (c *Constructor) encodeRaw(data []byte) ([][]byte, error) {
	shards, err := c.enc.Split(data)
	if err != nil {
		return nil, err
	}
	if err := c.enc.Encode(shards); err != nil {
		return nil, err
	}
	return shards, nil
}