// Copyright 2018 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package etcdserverpb

import (
	"fmt"
	"strings"

	proto "github.com/golang/protobuf/proto"
)

// InternalRaftStringer implements custom proto Stringer:
// redact password, replace value fields with value_size fields.
type InternalRaftStringer struct {
	Request *InternalRaftRequest
}

func (as *InternalRaftStringer) String() string {
	switch {
	case as.Request.LeaseGrant != nil:
		return fmt.Sprintf("header:<%s> lease_grant:<ttl:%d-second id:%016x>",
			as.Request.Header.String(),
			as.Request.LeaseGrant.TTL,
			as.Request.LeaseGrant.ID,
		)
	case as.Request.LeaseRevoke != nil:
		return fmt.Sprintf("header:<%s> lease_revoke:<id:%016x>",
			as.Request.Header.String(),
			as.Request.LeaseRevoke.ID,
		)
	case as.Request.Authenticate != nil:
		return fmt.Sprintf("header:<%s> authenticate:<name:%s simple_token:%s>",
			as.Request.Header.String(),
			as.Request.Authenticate.Name,
			as.Request.Authenticate.SimpleToken,
		)
	case as.Request.AuthUserAdd != nil:
		return fmt.Sprintf("header:<%s> auth_user_add:<name:%s>",
			as.Request.Header.String(),
			as.Request.AuthUserAdd.Name,
		)
	case as.Request.AuthUserChangePassword != nil:
		return fmt.Sprintf("header:<%s> auth_user_change_password:<name:%s>",
			as.Request.Header.String(),
			as.Request.AuthUserChangePassword.Name,
		)
	case as.Request.Put != nil:
		return fmt.Sprintf("header:<%s> put:<%s>",
			as.Request.Header.String(),
			NewLoggablePutRequest(as.Request.Put).String(),
		)
	case as.Request.Txn != nil:
		return fmt.Sprintf("header:<%s> txn:<%s>",
			as.Request.Header.String(),
			NewLoggableTxnRequest(as.Request.Txn).String(),
		)
	default:
		// nothing to redact
	}
	return as.Request.String()
}

// txnRequestStringer implements a custom proto String to replace value bytes fields with value size
// fields in any nested txn and put operations.
type txnRequestStringer struct {
	Request *TxnRequest
}

func NewLoggableTxnRequest(request *TxnRequest) *txnRequestStringer {
	return &txnRequestStringer{request}
}

func (as *txnRequestStringer) String() string {
	var compare []string
	for _, c := range as.Request.Compare {
		switch cv := c.TargetUnion.(type) {
		case *Compare_Value:
			compare = append(compare, newLoggableValueCompare(c, cv).String())
		default:
			// nothing to redact
			compare = append(compare, c.String())
		}
	}
	var success []string
	for _, s := range as.Request.Success {
		success = append(success, newLoggableRequestOp(s).String())
	}
	var failure []string
	for _, f := range as.Request.Failure {
		failure = append(failure, newLoggableRequestOp(f).String())
	}
	return fmt.Sprintf("compare:<%s> success:<%s> failure:<%s>",
		strings.Join(compare, " "),
		strings.Join(success, " "),
		strings.Join(failure, " "),
	)
}

// requestOpStringer implements a custom proto String to replace value bytes fields with value
// size fields in any nested txn and put operations.
type requestOpStringer struct {
	Op *RequestOp
}

func newLoggableRequestOp(op *RequestOp) *requestOpStringer {
	return &requestOpStringer{op}
}

func (as *requestOpStringer) String() string {
	switch op := as.Op.Request.(type) {
	case *RequestOp_RequestPut:
		return fmt.Sprintf("request_put:<%s>", NewLoggablePutRequest(op.RequestPut).String())
	case *RequestOp_RequestTxn:
		return fmt.Sprintf("request_txn:<%s>", NewLoggableTxnRequest(op.RequestTxn).String())
	default:
		// nothing to redact
	}
	return as.Op.String()
}

// loggableValueCompare implements a custom proto String for Compare.Value union member types to
// replace the value bytes field with a value size field.
// To preserve proto encoding of the key and range_end bytes, a faked out proto type is used here.
type loggableValueCompare struct {
	Result    Compare_CompareResult `protobuf:"varint,1,opt,name=result,proto3,enum=etcdserverpb.Compare_CompareResult"`
	Target    Compare_CompareTarget `protobuf:"varint,2,opt,name=target,proto3,enum=etcdserverpb.Compare_CompareTarget"`
	Key       []byte                `protobuf:"bytes,3,opt,name=key,proto3"`
	ValueSize int                   `protobuf:"bytes,7,opt,name=value_size,proto3"`
	RangeEnd  []byte                `protobuf:"bytes,64,opt,name=range_end,proto3"`
}

func newLoggableValueCompare(c *Compare, cv *Compare_Value) *loggableValueCompare {
	return &loggableValueCompare{
		c.Result,
		c.Target,
		c.Key,
		len(cv.Value),
		c.RangeEnd,
	}
}

func (m *loggableValueCompare) Reset()         { *m = loggableValueCompare{} }
func (m *loggableValueCompare) String() string { return proto.CompactTextString(m) }
func (*loggableValueCompare) ProtoMessage()    {}

// loggablePutRequest implements a custom proto String to replace value bytes field with a value
// size field.
// To preserve proto encoding of the key bytes, a faked out proto type is used here.
type loggablePutRequest struct {
	Key         []byte `protobuf:"bytes,1,opt,name=key,proto3"`
	ValueSize   int    `protobuf:"varint,2,opt,name=value_size,proto3"`
	Lease       int64  `protobuf:"varint,3,opt,name=lease,proto3"`
	PrevKv      bool   `protobuf:"varint,4,opt,name=prev_kv,proto3"`
	IgnoreValue bool   `protobuf:"varint,5,opt,name=ignore_value,proto3"`
	IgnoreLease bool   `protobuf:"varint,6,opt,name=ignore_lease,proto3"`
}

func NewLoggablePutRequest(request *PutRequest) *loggablePutRequest {
	return &loggablePutRequest{
		request.Key,
		len(request.Value),
		request.Lease,
		request.PrevKv,
		request.IgnoreValue,
		request.IgnoreLease,
	}
}

func (m *loggablePutRequest) Reset()         { *m = loggablePutRequest{} }
func (m *loggablePutRequest) String() string { return proto.CompactTextString(m) }
func (*loggablePutRequest) ProtoMessage()    {}
