package ape

import (
	"fmt"

	ape "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape/grpc"
	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/message"
	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/proto"
)

const (
	chainTargetTargetTypeField = 1
	chainTargetNameField       = 2

	chainRawField = 1
)

func (t *ChainTarget) StableSize() (size int) {
	if t == nil {
		return 0
	}

	size += proto.EnumSize(chainTargetTargetTypeField, int32(t.targeType))
	size += proto.StringSize(chainTargetNameField, t.name)

	return size
}

func (t *ChainTarget) StableMarshal(buf []byte) []byte {
	if t == nil {
		return []byte{}
	}

	if buf == nil {
		buf = make([]byte, t.StableSize())
	}

	var offset int

	offset += proto.EnumMarshal(chainTargetTargetTypeField, buf[offset:], int32(t.targeType))
	proto.StringMarshal(chainTargetNameField, buf[offset:], t.name)

	return buf
}

func (t *ChainTarget) Unmarshal(data []byte) error {
	return message.Unmarshal(t, data, new(ape.ChainTarget))
}

func (c *Chain) StableSize() (size int) {
	if c == nil {
		return 0
	}

	switch v := c.GetKind().(type) {
	case *ChainRaw:
		if v != nil {
			size += proto.BytesSize(chainRawField, v.GetRaw())
		}
	default:
		panic(fmt.Sprintf("unsupported chain kind: %T", v))
	}

	return size
}

func (c *Chain) StableMarshal(buf []byte) []byte {
	if c == nil {
		return []byte{}
	}

	if buf == nil {
		buf = make([]byte, c.StableSize())
	}

	var offset int

	switch v := c.GetKind().(type) {
	case *ChainRaw:
		if v != nil {
			proto.BytesMarshal(chainRawField, buf[offset:], v.GetRaw())
		}
	default:
		panic(fmt.Sprintf("unsupported chain kind: %T", v))
	}

	return buf
}

func (c *Chain) Unmarshal(data []byte) error {
	return message.Unmarshal(c, data, new(ape.Chain))
}