// Copyright 2016 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 prpc

// This file implements encoding of RPC results to HTTP responses.

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"net/http"
	"sort"
	"strconv"

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

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/grpc/grpcutil"
)

const (
	headerAccept = "Accept"
)

// responseFormat returns the format to be used in a response.
// Can return only FormatBinary (preferred), FormatJSONPB or FormatText.
// In case of an error, format is undefined.
func responseFormat(acceptHeader string) (Format, *protocolError) {
	if acceptHeader == "" {
		return FormatBinary, nil
	}

	parsed, err := parseAccept(acceptHeader)
	if err != nil {
		return FormatBinary, errorf(http.StatusBadRequest, "Accept header: %s", err)
	}
	formats := make(acceptFormatSlice, 0, len(parsed))
	for _, at := range parsed {
		f, err := FormatFromMediaType(at.MediaType, at.MediaTypeParams)
		if err != nil {
			// Ignore invalid format. Check further.
			continue
		}
		formats = append(formats, acceptFormat{f, at.QualityFactor})
	}
	if len(formats) == 0 {
		return FormatBinary, errorf(
			http.StatusNotAcceptable,
			"Accept header: specified media types are not not supported. Supported types: %q, %q, %q, %q.",
			FormatBinary.MediaType(),
			FormatJSONPB.MediaType(),
			FormatText.MediaType(),
			ContentTypeJSON,
		)
	}
	sort.Sort(formats) // order by quality factor and format preference.
	return formats[0].Format, nil
}

// writeMessage writes msg to w in the specified format.
// c is used to log errors.
// panics if msg is nil.
func writeMessage(c context.Context, w http.ResponseWriter, msg proto.Message, format Format) {
	if msg == nil {
		panic("msg is nil")
	}

	var body []byte
	var err error
	switch format {
	case FormatBinary:
		body, err = proto.Marshal(msg)

	case FormatJSONPB:
		var buf bytes.Buffer
		buf.WriteString(JSONPBPrefix)
		m := jsonpb.Marshaler{}
		err = m.Marshal(&buf, msg)
		if err == nil {
			_, err = buf.WriteRune('\n')
		}
		body = buf.Bytes()

	case FormatText:
		var buf bytes.Buffer
		err = proto.MarshalText(&buf, msg)
		body = buf.Bytes()

	default:
		panic(fmt.Errorf("impossible: invalid format %d", format))

	}
	if err != nil {
		writeError(c, w, withCode(err, codes.Internal))
		return
	}

	w.Header().Set(HeaderGRPCCode, strconv.Itoa(int(codes.OK)))
	w.Header().Set(headerContentType, format.MediaType())
	w.Header().Set("X-Content-Type-Options", "nosniff")
	if _, err := w.Write(body); err != nil {
		logging.WithError(err).Errorf(c, "prpc: failed to write response body")
	}
}

// errorCode returns a most appropriate gRPC code for an error
func errorCode(err error) codes.Code {
	switch errors.Unwrap(err) {
	case context.DeadlineExceeded:
		return codes.DeadlineExceeded

	case context.Canceled:
		return codes.Canceled

	default:
		return grpc.Code(err)
	}
}

// writeError writes err to w and logs it.
func writeError(c context.Context, w http.ResponseWriter, err error) {
	var code codes.Code
	var httpStatus int
	var msg string
	if perr, ok := err.(*protocolError); ok {
		code = codes.InvalidArgument
		msg = perr.err.Error()
		httpStatus = perr.status
	} else {
		code = errorCode(err)
		msg = grpc.ErrorDesc(err)
		httpStatus = grpcutil.CodeStatus(code)
	}

	body := msg
	level := logging.Warning
	if httpStatus >= 500 {
		level = logging.Error
		// Hide potential implementation details from the user.
		body = http.StatusText(httpStatus)
	}
	logging.Logf(c, level, "prpc: responding with %s error: %s", code, msg)

	w.Header().Set(HeaderGRPCCode, strconv.Itoa(int(code)))
	w.Header().Set(headerContentType, "text/plain")
	w.WriteHeader(httpStatus)
	if _, err := io.WriteString(w, body); err != nil {
		logging.WithError(err).Errorf(c, "prpc: failed to write response body")
		// The header is already written. There is nothing more we can do.
		return
	}
	io.WriteString(w, "\n")
}

func withCode(err error, c codes.Code) error {
	return status.Error(c, err.Error())
}
