// Copyright 2018 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.

package encoding_test

import (
	"flag"
	"fmt"
	"testing"

	jsonpbV1 "github.com/golang/protobuf/jsonpb"
	protoV1 "github.com/golang/protobuf/proto"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/encoding/prototext"
	pref "google.golang.org/protobuf/reflect/protoreflect"

	tpb "google.golang.org/protobuf/internal/testprotos/test"
)

// The results of these microbenchmarks are unlikely to correspond well
// to real world peformance. They are mainly useful as a quick check to
// detect unexpected regressions and for profiling specific cases.

var benchV1 = flag.Bool("v1", false, "benchmark the v1 implementation")

const (
	boolValue  = true
	intValue   = 1 << 30
	floatValue = 3.14159265
	strValue   = "hello world"

	maxRecurseLevel = 3
)

func makeProto() *tpb.TestAllTypes {
	m := &tpb.TestAllTypes{}
	fillMessage(m.ProtoReflect(), 0)
	return m
}

func fillMessage(m pref.Message, level int) {
	if level > maxRecurseLevel {
		return
	}

	fieldDescs := m.Descriptor().Fields()
	for i := 0; i < fieldDescs.Len(); i++ {
		fd := fieldDescs.Get(i)
		switch {
		case fd.IsList():
			setList(m.Mutable(fd).List(), fd, level)
		case fd.IsMap():
			setMap(m.Mutable(fd).Map(), fd, level)
		default:
			setScalarField(m, fd, level)
		}
	}
}

func setScalarField(m pref.Message, fd pref.FieldDescriptor, level int) {
	switch fd.Kind() {
	case pref.MessageKind, pref.GroupKind:
		m2 := m.NewMessage(fd)
		fillMessage(m2, level+1)
		m.Set(fd, pref.ValueOf(m2))
	default:
		m.Set(fd, scalarField(fd.Kind()))
	}
}

func scalarField(kind pref.Kind) pref.Value {
	switch kind {
	case pref.BoolKind:
		return pref.ValueOf(boolValue)

	case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
		return pref.ValueOf(int32(intValue))

	case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
		return pref.ValueOf(int64(intValue))

	case pref.Uint32Kind, pref.Fixed32Kind:
		return pref.ValueOf(uint32(intValue))

	case pref.Uint64Kind, pref.Fixed64Kind:
		return pref.ValueOf(uint64(intValue))

	case pref.FloatKind:
		return pref.ValueOf(float32(floatValue))

	case pref.DoubleKind:
		return pref.ValueOf(float64(floatValue))

	case pref.BytesKind:
		return pref.ValueOf([]byte(strValue))

	case pref.StringKind:
		return pref.ValueOf(strValue)

	case pref.EnumKind:
		return pref.ValueOf(pref.EnumNumber(42))
	}

	panic(fmt.Sprintf("FieldDescriptor.Kind %v is not valid", kind))
}

func setList(list pref.List, fd pref.FieldDescriptor, level int) {
	switch fd.Kind() {
	case pref.MessageKind, pref.GroupKind:
		for i := 0; i < 10; i++ {
			m := list.NewMessage()
			fillMessage(m, level+1)
			list.Append(pref.ValueOf(m))
		}
	default:
		for i := 0; i < 100; i++ {
			list.Append(scalarField(fd.Kind()))
		}
	}
}

func setMap(mmap pref.Map, fd pref.FieldDescriptor, level int) {
	fields := fd.Message().Fields()
	keyDesc := fields.ByNumber(1)
	valDesc := fields.ByNumber(2)

	pkey := scalarField(keyDesc.Kind())
	switch kind := valDesc.Kind(); kind {
	case pref.MessageKind, pref.GroupKind:
		m := mmap.NewMessage()
		fillMessage(m, level+1)
		mmap.Set(pkey.MapKey(), pref.ValueOf(m))
	default:
		mmap.Set(pkey.MapKey(), scalarField(kind))
	}
}

func BenchmarkTextEncode(b *testing.B) {
	m := makeProto()
	for i := 0; i < b.N; i++ {
		if *benchV1 {
			protoV1.MarshalTextString(m)
		} else {
			_, err := prototext.MarshalOptions{Indent: "  "}.Marshal(m)
			if err != nil {
				b.Fatal(err)
			}
		}
	}
}

func BenchmarkTextDecode(b *testing.B) {
	m := makeProto()
	in, err := prototext.MarshalOptions{Indent: "  "}.Marshal(m)
	if err != nil {
		b.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		m := &tpb.TestAllTypes{}
		var err error
		if *benchV1 {
			err = protoV1.UnmarshalText(string(in), m)
		} else {
			err = prototext.Unmarshal(in, m)
		}
		if err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkJSONEncode(b *testing.B) {
	m := makeProto()
	for i := 0; i < b.N; i++ {
		var err error
		if *benchV1 {
			jsm := &jsonpbV1.Marshaler{Indent: "  "}
			_, err = jsm.MarshalToString(m)
		} else {
			_, err = protojson.MarshalOptions{Indent: "  "}.Marshal(m)
		}
		if err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkJSONDecode(b *testing.B) {
	m := makeProto()
	out, err := protojson.MarshalOptions{Indent: "  "}.Marshal(m)
	if err != nil {
		b.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		m := &tpb.TestAllTypes{}
		var err error
		if *benchV1 {
			err = jsonpbV1.UnmarshalString(string(out), m)
		} else {
			err = protojson.Unmarshal(out, m)
		}
		if err != nil {
			b.Fatal(err)
		}
	}
}
