package pbmsg

import (
	"code.justin.tv/release/trace/api"
	"code.justin.tv/release/trace/common"
	"code.justin.tv/release/trace/pbmsg/iana"
	"code.justin.tv/release/trace/pbmsg/memcached"
)

// DowngradeTransaction converts a proto3-syntax TransactionSet into a
// slice of proto2, old style Transactions. This is deprecated.
func DowngradeTransactionSet(ts *api.TransactionSet) []*Transaction {
	out := make([]*Transaction, len(ts.GetTransaction()))
	for i, tx := range ts.GetTransaction() {
		out[i] = DowngradeTransaction(tx)
	}
	return out
}

// DowngradeTransaction converts a proto3-syntax Transaction into a
// proto2, old style one. This is deprecated.
func DowngradeTransaction(in *api.Transaction) (out *Transaction) {
	out = &Transaction{
		TransactionId: in.TransactionId,
		Root:          downgradeCall(in.GetRoot()),
		Client:        downgradeService(in.GetClient()),
	}

	return out
}

func downgradeCall(in *api.Call) (out *Call) {
	if in == nil {
		return nil
	}

	subcalls := make([]*Call, len(in.GetSubcalls()))
	for i, sc := range in.GetSubcalls() {
		subcalls[i] = downgradeCall(sc)
	}

	out = &Call{
		Subcalls:          subcalls,
		Path:              in.Path,
		Svc:               downgradeService(in.GetSvc()),
		Params:            downgradeParams(in.GetParams()),
		ClientTimestamps:  downgradeTimestamps(in.GetClientTimestamps()),
		ServiceTimestamps: downgradeTimestamps(in.GetServiceTimestamps()),
		RequestSentTo:     downgradeString(in.RequestSentTo),
	}

	return out
}

func downgradeService(in *api.Service) (out *Service) {
	if in == nil {
		return nil
	}

	return &Service{
		Name: downgradeString(in.Name),
		Host: downgradeString(in.Host),
		Pid:  downgradeInt32(in.Pid),
		Peer: downgradeString(in.Peer),
	}
}

func downgradeTimestamps(in []*api.Timestamp) (out []*Timestamp) {
	if in == nil {
		return nil
	}

	out = make([]*Timestamp, len(in))
	for i, inTS := range in {
		out[i] = &Timestamp{
			Time: downgradeInt64(inTS.Time),
			Kind: downgradeKind(inTS.Kind),
		}
	}
	return out
}

func downgradeKind(in common.Kind) (out *Event_Kind) {
	return Event_Kind(in).Enum()
}

func downgradeParams(in *api.RPCParams) (out *RPCParams) {
	if in == nil {
		return nil
	}
	return &RPCParams{
		Http:      downgradeHTTPParams(in.GetHttp()),
		Sql:       downgradeSQLParams(in.GetSql()),
		Grpc:      downgradeGRPCParams(in.GetGrpc()),
		Memcached: downgradeMemcachedParams(in.GetMemcached()),
	}
}

func downgradeHTTPParams(in *api.HTTPParams) (out *HTTPParams) {
	if in == nil {
		return nil
	}
	return &HTTPParams{
		UriPath: downgradeString(in.UriPath),
		Status:  downgradeInt32(in.Status),
		Method:  downgradeMethod(in.Method),
		Route:   downgradeString(in.Route),
	}
}

func downgradeMethod(in common.Method) (out *iana.HTTPMethod) {
	return iana.HTTPMethod(in).Enum()
}

func downgradeSQLParams(in *api.SQLParams) (out *SQLParams) {
	if in == nil {
		return nil
	}

	return &SQLParams{
		Dbname:        downgradeString(in.Dbname),
		Dbuser:        downgradeString(in.Dbuser),
		StrippedQuery: downgradeString(in.StrippedQuery),
		Tables:        in.Tables,
	}
}

func downgradeGRPCParams(in *api.GRPCParams) (out *GRPCParams) {
	if in == nil {
		return nil
	}
	return &GRPCParams{
		Method: downgradeString(in.Method),
	}
}

func downgradeMemcachedParams(in *api.MemcachedParams) (out *MemcachedParams) {
	if in == nil {
		return nil
	}
	return &MemcachedParams{
		Command:       memcached.Command(memcached.Command_value[in.Command.String()]).Enum(),
		NKeysRequest:  downgradeUint32(in.NKeysRequest),
		NKeysResponse: downgradeUint32(in.NKeysResponse),
	}
}

func downgradeString(in string) (out *string) {
	if in == "" {
		return nil
	}
	return &in
}

func downgradeInt32(in int32) (out *int32) {
	if in == 0 {
		return nil
	}
	return &in
}

func downgradeUint32(in uint32) (out *uint32) {
	if in == 0 {
		return nil
	}
	return &in
}

func downgradeInt64(in int64) (out *int64) {
	if in == 0 {
		return nil
	}
	return &in
}
