package ape

import (
	"fmt"

	ape "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/grpc"
	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc"
	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message"
)

func TargetTypeToGRPCField(typ TargetType) ape.TargetType {
	switch typ {
	case TargetTypeNamespace:
		return ape.TargetType_NAMESPACE
	case TargetTypeContainer:
		return ape.TargetType_CONTAINER
	case TargetTypeUser:
		return ape.TargetType_USER
	case TargetTypeGroup:
		return ape.TargetType_GROUP
	default:
		return ape.TargetType_UNDEFINED
	}
}

func TargetTypeFromGRPCField(typ ape.TargetType) TargetType {
	switch typ {
	case ape.TargetType_NAMESPACE:
		return TargetTypeNamespace
	case ape.TargetType_CONTAINER:
		return TargetTypeContainer
	case ape.TargetType_USER:
		return TargetTypeUser
	case ape.TargetType_GROUP:
		return TargetTypeGroup
	default:
		return TargetTypeUndefined
	}
}

func TargetTypeToGRPC(typ TargetType) ape.TargetType {
	return ape.TargetType(typ)
}

func TargetTypeFromGRPC(typ ape.TargetType) TargetType {
	return TargetType(typ)
}

func (v2 *ChainTarget) ToGRPCMessage() grpc.Message {
	var mgrpc *ape.ChainTarget

	if v2 != nil {
		mgrpc = new(ape.ChainTarget)

		mgrpc.SetType(TargetTypeToGRPC(v2.GetTargetType()))
		mgrpc.SetName(v2.GetName())
	}

	return mgrpc
}

func (v2 *ChainTarget) FromGRPCMessage(m grpc.Message) error {
	mgrpc, ok := m.(*ape.ChainTarget)
	if !ok {
		return message.NewUnexpectedMessageType(m, mgrpc)
	}

	v2.SetTargetType(TargetTypeFromGRPC(mgrpc.GetType()))
	v2.SetName(mgrpc.GetName())

	return nil
}

func (v2 *ChainRaw) ToGRPCMessage() grpc.Message {
	var mgrpc *ape.Chain_Raw

	if v2 != nil {
		mgrpc = new(ape.Chain_Raw)

		mgrpc.SetRaw(v2.GetRaw())
	}

	return mgrpc
}

func (v2 *ChainRaw) FromGRPCMessage(m grpc.Message) error {
	mgrpc, ok := m.(*ape.Chain_Raw)
	if !ok {
		return message.NewUnexpectedMessageType(m, mgrpc)
	}

	v2.SetRaw(mgrpc.GetRaw())

	return nil
}

func (v2 *Chain) ToGRPCMessage() grpc.Message {
	var mgrpc *ape.Chain

	if v2 != nil {
		mgrpc = new(ape.Chain)

		switch chainKind := v2.GetKind().(type) {
		default:
			panic(fmt.Sprintf("unsupported chain kind: %T", chainKind))
		case *ChainRaw:
			mgrpc.SetKind(chainKind.ToGRPCMessage().(*ape.Chain_Raw))
		}
	}

	return mgrpc
}

func (v2 *Chain) FromGRPCMessage(m grpc.Message) error {
	mgrpc, ok := m.(*ape.Chain)
	if !ok {
		return message.NewUnexpectedMessageType(m, mgrpc)
	}

	switch chainKind := mgrpc.GetKind().(type) {
	default:
		return fmt.Errorf("unsupported chain kind: %T", chainKind)
	case *ape.Chain_Raw:
		chainRaw := new(ChainRaw)
		if err := chainRaw.FromGRPCMessage(chainKind); err != nil {
			return err
		}
		v2.SetKind(chainRaw)
	}

	return nil
}