// Copyright 2019 The LUCI 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 exe

import (
	"bytes"
	"encoding/json"

	"github.com/golang/protobuf/jsonpb"
	"github.com/golang/protobuf/proto"
	structpb "github.com/golang/protobuf/ptypes/struct"

	"go.chromium.org/luci/common/errors"
)

// ParseProperties interprets a protobuf 'struct' as structured Go data.
//
// `outputs` is a mapping of a property name to an output structure. An output
// structure may be one of two things:
//
//  * a non-nil proto.Message. The data in this field will be interpreted as
//    JSONPB and Unmarshaled into the proto.Message.
//  * a valid "encoding/json" unmarshal target. The data in this field will be
//    unmarshaled into with the stdlib "encoding/json" package.
//
// This function will scan the props (usually `build.Input.Properties`) and
// unmarshal them as appropriate into the outputs.
//
// Example:
//
//   myProto := &myprotos.Message{}
//   myStruct := &MyStruct{}
//   err := ParseProperties(build.Input.Properties, map[string]interface{}{
//     "proto": myProto, "$namespaced/struct": myStruct})
//   // handle err :)
//   fmt.Println("Got:", myProto.Field)
//   fmt.Println("Got:", myStruct.Field)
func ParseProperties(props *structpb.Struct, outputs map[string]interface{}) error {
	ret := errors.NewLazyMultiError(len(outputs))

	idx := -1
	for field, output := range outputs {
		idx++

		val := props.Fields[field]
		if val == nil {
			continue
		}

		var jsonBuf bytes.Buffer
		if err := (&jsonpb.Marshaler{}).Marshal(&jsonBuf, val); err != nil {
			ret.Assign(idx, errors.Annotate(err, "marshaling %q", field).Err())
			continue
		}

		var err error
		switch x := output.(type) {
		case proto.Message:
			err = jsonpb.Unmarshal(&jsonBuf, x)
		default:
			err = json.NewDecoder(&jsonBuf).Decode(x)
		}

		ret.Assign(idx, errors.Annotate(err, "unmarshalling %q", field).Err())
	}

	return ret.Get()
}

type nullType struct{}

// Null is a sentinel value to assign JSON `null` to a property with
// WriteProperties.
var Null = nullType{}

// WriteProperties updates a protobuf 'struct' with structured Go data.
//
// `inputs` is a mapping of a property name to an input structure. An input
// structure may be one of two things:
//
//  * a non-nil proto.Message. The data in this field will be interpreted as
//    JSONPB and Unmarshaled into the proto.Message.
//  * a valid "encoding/json" marshal source. The data in this field will be
//    interpreted as json and marshaled with the stdlib "encoding/json" package.
//  * The `Null` value in this package. The top-level property will be set to
//    JSON `null`.
//  * nil. The top-level property will be removed.
//
// This function will scan the inputs and marshal them as appropriate into
// `props` (usually `build.Output.Properties`).
//
// Example:
//
//   myProto := &myprotos.Message{Field: "something"}
//   myStruct := &MyStruct{Field: 100}
//   err := WriteProperties(build.Output.Properties, map[string]interface{}{
//     "proto": myProto, "$namespaced/struct": myStruct})
//   // handle err :)
func WriteProperties(props *structpb.Struct, inputs map[string]interface{}) error {
	if props.Fields == nil {
		props.Fields = make(map[string]*structpb.Value, len(inputs))
	}

	ret := errors.NewLazyMultiError(len(inputs))

	idx := -1
	for field, input := range inputs {
		idx++

		if input == nil {
			delete(props.Fields, field)
			continue
		}

		var buf bytes.Buffer
		var err error

		fieldVal := props.Fields[field]
		if fieldVal == nil {
			fieldVal = &structpb.Value{}
			props.Fields[field] = fieldVal
		}

		switch x := input.(type) {
		case nullType:
			fieldVal.Kind = &structpb.Value_NullValue{}
			continue

		case proto.Message:
			err = (&jsonpb.Marshaler{OrigName: true}).Marshal(&buf, x)

		default:
			var data []byte
			data, err = json.Marshal(x)
			buf.Write(data)
		}

		if err != nil {
			ret.Assign(idx, errors.Annotate(err, "marshaling %q", field).Err())
			continue
		}

		ret.Assign(idx, errors.Annotate(
			jsonpb.Unmarshal(&buf, fieldVal), "unmarshalling %q", field,
		).Err())
	}

	return ret.Get()
}
