// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Protocol buffer deep copy and merge.
// TODO: RawMessage.

package proto

import (
	"fmt"
	"log"
	"reflect"
	"strings"

	"github.com/golang/protobuf/protoapi"
	"github.com/golang/protobuf/v2/reflect/protoreflect"
)

// Clone returns a deep copy of a protocol buffer.
func Clone(src Message) Message {
	in := reflect.ValueOf(src)
	if in.IsNil() {
		return src
	}
	out := reflect.New(in.Type().Elem())
	dst := out.Interface().(Message)
	Merge(dst, src)
	return dst
}

// Merger is the interface representing objects that can merge messages of the same type.
type Merger interface {
	// Merge merges src into this message.
	// Required and optional fields that are set in src will be set to that value in dst.
	// Elements of repeated fields will be appended.
	//
	// Merge may panic if called with a different argument type than the receiver.
	Merge(src Message)
}

// generatedMerger is the custom merge method that generated protos will have.
// We must add this method since a generate Merge method will conflict with
// many existing protos that have a Merge data field already defined.
type generatedMerger interface {
	XXX_Merge(src Message)
}

// Merge merges src into dst.
// Required and optional fields that are set in src will be set to that value in dst.
// Elements of repeated fields will be appended.
// Merge panics if src and dst are not the same type, or if dst is nil.
func Merge(dst, src Message) {
	if m, ok := dst.(Merger); ok {
		m.Merge(src)
		return
	}

	in := reflect.ValueOf(src)
	out := reflect.ValueOf(dst)
	if out.IsNil() {
		panic("proto: nil destination")
	}
	if in.Type() != out.Type() {
		panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src))
	}
	if in.IsNil() {
		return // Merge from nil src is a noop
	}
	if m, ok := dst.(generatedMerger); ok {
		m.XXX_Merge(src)
		return
	}
	mergeStruct(out.Elem(), in.Elem())
}

func mergeStruct(out, in reflect.Value) {
	sprop := GetProperties(in.Type())
	for i := 0; i < in.NumField(); i++ {
		f := in.Type().Field(i)
		if strings.HasPrefix(f.Name, "XXX_") {
			continue
		}
		mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
	}

	if emIn, err := extendable(in.Addr().Interface()); err == nil {
		emOut, _ := extendable(out.Addr().Interface())
		if emIn.HasInit() {
			emIn.Lock()
			mergeExtension(emOut, emIn)
			emIn.Unlock()
		}
	}

	uf := in.FieldByName("XXX_unrecognized")
	if !uf.IsValid() {
		return
	}
	uin := uf.Bytes()
	if len(uin) > 0 {
		out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...))
	}
}

// mergeAny performs a merge between two values of the same type.
// viaPtr indicates whether the values were indirected through a pointer (implying proto2).
// prop is set if this is a struct field (it may be nil).
func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) {
	if in.Type() == protoMessageType {
		if !in.IsNil() {
			if out.IsNil() {
				out.Set(reflect.ValueOf(Clone(in.Interface().(Message))))
			} else {
				Merge(out.Interface().(Message), in.Interface().(Message))
			}
		}
		return
	}
	switch in.Kind() {
	case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
		reflect.String, reflect.Uint32, reflect.Uint64:
		if !viaPtr && isProto3Zero(in) {
			return
		}
		out.Set(in)
	case reflect.Interface:
		// Probably a oneof field; copy non-nil values.
		if in.IsNil() {
			return
		}
		// Allocate destination if it is not set, or set to a different type.
		// Otherwise we will merge as normal.
		if out.IsNil() || out.Elem().Type() != in.Elem().Type() {
			out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
		}
		mergeAny(out.Elem(), in.Elem(), false, nil)
	case reflect.Map:
		if in.Len() == 0 {
			return
		}
		if out.IsNil() {
			out.Set(reflect.MakeMap(in.Type()))
		}
		// For maps with value types of *T or []byte we need to deep copy each value.
		elemKind := in.Type().Elem().Kind()
		for _, key := range in.MapKeys() {
			var val reflect.Value
			switch elemKind {
			case reflect.Ptr:
				val = reflect.New(in.Type().Elem().Elem())
				mergeAny(val, in.MapIndex(key), false, nil)
			case reflect.Slice:
				val = in.MapIndex(key)
				val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
			default:
				val = in.MapIndex(key)
			}
			out.SetMapIndex(key, val)
		}
	case reflect.Ptr:
		if in.IsNil() {
			return
		}
		if out.IsNil() {
			out.Set(reflect.New(in.Elem().Type()))
		}
		mergeAny(out.Elem(), in.Elem(), true, nil)
	case reflect.Slice:
		if in.IsNil() {
			return
		}
		if in.Type().Elem().Kind() == reflect.Uint8 {
			// []byte is a scalar bytes field, not a repeated field.

			// Edge case: if this is in a proto3 message, a zero length
			// bytes field is considered the zero value, and should not
			// be merged.
			if prop != nil && prop.Proto3 && in.Len() == 0 {
				return
			}

			// Make a deep copy.
			// Append to []byte{} instead of []byte(nil) so that we never end up
			// with a nil result.
			out.SetBytes(append([]byte{}, in.Bytes()...))
			return
		}
		n := in.Len()
		if out.IsNil() {
			out.Set(reflect.MakeSlice(in.Type(), 0, n))
		}
		switch in.Type().Elem().Kind() {
		case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
			reflect.String, reflect.Uint32, reflect.Uint64:
			out.Set(reflect.AppendSlice(out, in))
		default:
			for i := 0; i < n; i++ {
				x := reflect.Indirect(reflect.New(in.Type().Elem()))
				mergeAny(x, in.Index(i), false, nil)
				out.Set(reflect.Append(out, x))
			}
		}
	case reflect.Struct:
		mergeStruct(out, in)
	default:
		// unknown type, so not a protocol buffer
		log.Printf("proto: don't know how to copy %v", in)
	}
}

func mergeExtension(out, in protoapi.ExtensionFields) {
	in.Range(func(extNum protoreflect.FieldNumber, eIn Extension) bool {
		eOut := Extension{Desc: eIn.Desc}
		if eIn.Value != nil {
			v := reflect.New(reflect.TypeOf(eIn.Value)).Elem()
			mergeAny(v, reflect.ValueOf(eIn.Value), false, nil)
			eOut.Value = v.Interface()
		}
		if eIn.Raw != nil {
			eOut.Raw = make([]byte, len(eIn.Raw))
			copy(eOut.Raw, eIn.Raw)
		}

		out.Set(extNum, eOut)
		return true
	})
}
