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

//go:build goexperiment.jsonv2

package json

import (
	"cmp"
	"errors"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"
	"sync"

	"encoding/json/internal/jsonflags"
	"encoding/json/internal/jsonopts"
	"encoding/json/internal/jsonwire"
	"encoding/json/jsontext"
)

// ErrUnknownName indicates that a JSON object member could not be
// unmarshaled because the name is not known to the target Go struct.
// This error is directly wrapped within a [SemanticError] when produced.
//
// The name of an unknown JSON object member can be extracted as:
//
//	err := ...
//	serr, ok := errors.AsType[*json.SemanticError](err)
//	if ok && serr.Err == json.ErrUnknownName {
//		ptr := serr.JSONPointer // JSON pointer to unknown name
//		name := ptr.LastToken() // unknown name itself
//		...
//	}
//
// This error is only returned if [RejectUnknownMembers] is true.
var ErrUnknownName = errors.New("unknown object member name")

const errorPrefix = "json: "

func isSemanticError(err error) bool {
	_, ok := err.(*SemanticError)
	return ok
}

func isSyntacticError(err error) bool {
	_, ok := err.(*jsontext.SyntacticError)
	return ok
}

// isFatalError reports whether this error must terminate asharling.
// All errors are considered fatal unless operating under
// [jsonflags.ReportErrorsWithLegacySemantics] in which case only
// syntactic errors and I/O errors are considered fatal.
func isFatalError(err error, flags jsonflags.Flags) bool {
	return !flags.Get(jsonflags.ReportErrorsWithLegacySemantics) ||
		isSyntacticError(err) || export.IsIOError(err)
}

// SemanticError describes an error determining the meaning
// of JSON data as Go data or vice-versa.
//
// If a [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom] method
// returns a SemanticError when called by the [json] package,
// then the ByteOffset, JSONPointer, and GoType fields are automatically
// populated by the calling context if they are the zero value.
//
// The contents of this error as produced by this package may change over time.
type SemanticError struct {
	requireKeyedLiterals
	nonComparable

	action string // either "marshal" or "unmarshal"

	// ByteOffset indicates that an error occurred after this byte offset.
	ByteOffset int64
	// JSONPointer indicates that an error occurred within this JSON value
	// as indicated using the JSON Pointer notation (see RFC 6901).
	JSONPointer jsontext.Pointer

	// JSONKind is the JSON kind that could not be handled.
	JSONKind jsontext.Kind // may be zero if unknown
	// JSONValue is the JSON number or string that could not be unmarshaled.
	// It is not populated during marshaling.
	JSONValue jsontext.Value // may be nil if irrelevant or unknown
	// GoType is the Go type that could not be handled.
	GoType reflect.Type // may be nil if unknown

	// Err is the underlying error.
	Err error // may be nil
}

// coder is implemented by [jsontext.Encoder] or [jsontext.Decoder].
type coder interface {
	StackPointer() jsontext.Pointer
	Options() Options
}

// newInvalidFormatError wraps err in a SemanticError because
// the current type t cannot handle the provided options format.
// This error must be called before producing or consuming the next value.
//
// If [jsonflags.ReportErrorsWithLegacySemantics] is specified,
// then this automatically skips the next value when unmarshaling
// to ensure that the value is fully consumed.
func newInvalidFormatError(c coder, t reflect.Type) error {
	err := fmt.Errorf("invalid format flag %q", c.Options().(*jsonopts.Struct).Format)
	switch c := c.(type) {
	case *jsontext.Encoder:
		err = newMarshalErrorBefore(c, t, err)
	case *jsontext.Decoder:
		err = newUnmarshalErrorBeforeWithSkipping(c, t, err)
	}
	return err
}

// newMarshalErrorBefore wraps err in a SemanticError assuming that e
// is positioned right before the next token or value, which causes an error.
func newMarshalErrorBefore(e *jsontext.Encoder, t reflect.Type, err error) error {
	return &SemanticError{action: "marshal", GoType: t, Err: toUnexpectedEOF(err),
		ByteOffset:  e.OutputOffset() + int64(export.Encoder(e).CountNextDelimWhitespace()),
		JSONPointer: jsontext.Pointer(export.Encoder(e).AppendStackPointer(nil, +1))}
}

// newUnmarshalErrorBefore wraps err in a SemanticError assuming that d
// is positioned right before the next token or value, which causes an error.
// It does not record the next JSON kind as this error is used to indicate
// the receiving Go value is invalid to unmarshal into (and not a JSON error).
// However, if [jsonflags.ReportErrorsWithLegacySemantics] is specified,
// then it does record the next JSON kind for historical reporting reasons.
func newUnmarshalErrorBefore(d *jsontext.Decoder, t reflect.Type, err error) error {
	var k jsontext.Kind
	if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
		k = d.PeekKind()
	}
	return &SemanticError{action: "unmarshal", GoType: t, Err: toUnexpectedEOF(err),
		ByteOffset:  d.InputOffset() + int64(export.Decoder(d).CountNextDelimWhitespace()),
		JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, +1)),
		JSONKind:    k}
}

// newUnmarshalErrorBeforeWithSkipping is like [newUnmarshalErrorBefore],
// but automatically skips the next value if
// [jsonflags.ReportErrorsWithLegacySemantics] is specified.
func newUnmarshalErrorBeforeWithSkipping(d *jsontext.Decoder, t reflect.Type, err error) error {
	err = newUnmarshalErrorBefore(d, t, err)
	if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
		if err2 := export.Decoder(d).SkipValue(); err2 != nil {
			return err2
		}
	}
	return err
}

// newUnmarshalErrorAfter wraps err in a SemanticError assuming that d
// is positioned right after the previous token or value, which caused an error.
func newUnmarshalErrorAfter(d *jsontext.Decoder, t reflect.Type, err error) error {
	tokOrVal := export.Decoder(d).PreviousTokenOrValue()
	return &SemanticError{action: "unmarshal", GoType: t, Err: toUnexpectedEOF(err),
		ByteOffset:  d.InputOffset() - int64(len(tokOrVal)),
		JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, -1)),
		JSONKind:    jsontext.Value(tokOrVal).Kind()}
}

// newUnmarshalErrorAfter wraps err in a SemanticError assuming that d
// is positioned right after the previous token or value, which caused an error.
// It also stores a copy of the last JSON value if it is a string or number.
func newUnmarshalErrorAfterWithValue(d *jsontext.Decoder, t reflect.Type, err error) error {
	serr := newUnmarshalErrorAfter(d, t, err).(*SemanticError)
	if serr.JSONKind == '"' || serr.JSONKind == '0' {
		serr.JSONValue = jsontext.Value(export.Decoder(d).PreviousTokenOrValue()).Clone()
	}
	return serr
}

// newUnmarshalErrorAfterWithSkipping is like [newUnmarshalErrorAfter],
// but automatically skips the remainder of the current value if
// [jsonflags.ReportErrorsWithLegacySemantics] is specified.
func newUnmarshalErrorAfterWithSkipping(d *jsontext.Decoder, t reflect.Type, err error) error {
	err = newUnmarshalErrorAfter(d, t, err)
	if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
		if err2 := export.Decoder(d).SkipValueRemainder(); err2 != nil {
			return err2
		}
	}
	return err
}

// newSemanticErrorWithPosition wraps err in a SemanticError assuming that
// the error occurred at the provided depth, and length.
// If err is already a SemanticError, then position information is only
// injected if it is currently unpopulated.
//
// If the position is unpopulated, it is ambiguous where the error occurred
// in the user code, whether it was before or after the current position.
// For the byte offset, we assume that the error occurred before the last read
// token or value when decoding, or before the next value when encoding.
// For the JSON pointer, we point to the parent object or array unless
// we can be certain that it happened with an object member.
//
// This is used to annotate errors returned by user-provided
// v2 MarshalJSON or UnmarshalJSON methods or functions.
func newSemanticErrorWithPosition(c coder, t reflect.Type, prevDepth int, prevLength int64, err error) error {
	serr, _ := err.(*SemanticError)
	if serr == nil {
		serr = &SemanticError{Err: err}
	}
	serr.Err = toUnexpectedEOF(serr.Err)
	var currDepth int
	var currLength int64
	var coderState interface{ AppendStackPointer([]byte, int) []byte }
	var offset int64
	switch c := c.(type) {
	case *jsontext.Encoder:
		e := export.Encoder(c)
		serr.action = cmp.Or(serr.action, "marshal")
		currDepth, currLength = e.Tokens.DepthLength()
		offset = c.OutputOffset() + int64(export.Encoder(c).CountNextDelimWhitespace())
		coderState = e
	case *jsontext.Decoder:
		d := export.Decoder(c)
		serr.action = cmp.Or(serr.action, "unmarshal")
		currDepth, currLength = d.Tokens.DepthLength()
		tokOrVal := d.PreviousTokenOrValue()
		offset = c.InputOffset() - int64(len(tokOrVal))
		if (prevDepth == currDepth && prevLength == currLength) || len(tokOrVal) == 0 {
			// If no Read method was called in the user-defined method or
			// if the Peek method was called, then use the offset of the next value.
			offset = c.InputOffset() + int64(export.Decoder(c).CountNextDelimWhitespace())
		}
		coderState = d
	}
	serr.ByteOffset = cmp.Or(serr.ByteOffset, offset)
	if serr.JSONPointer == "" {
		where := 0 // default to ambiguous positioning
		switch {
		case prevDepth == currDepth && prevLength+0 == currLength:
			where = +1
		case prevDepth == currDepth && prevLength+1 == currLength:
			where = -1
		}
		serr.JSONPointer = jsontext.Pointer(coderState.AppendStackPointer(nil, where))
	}
	serr.GoType = cmp.Or(serr.GoType, t)
	return serr
}

// collapseSemanticErrors collapses double SemanticErrors at the outer levels
// into a single SemanticError by preserving the inner error,
// but prepending the ByteOffset and JSONPointer with the outer error.
//
// For example:
//
//	collapseSemanticErrors(&SemanticError{
//		ByteOffset:  len64(`[0,{"alpha":[0,1,`),
//		JSONPointer: "/1/alpha/2",
//		GoType:      reflect.TypeFor[outerType](),
//		Err: &SemanticError{
//			ByteOffset:  len64(`{"foo":"bar","fizz":[0,`),
//			JSONPointer: "/fizz/1",
//			GoType:      reflect.TypeFor[innerType](),
//			Err:         ...,
//		},
//	})
//
// results in:
//
//	&SemanticError{
//		ByteOffset:  len64(`[0,{"alpha":[0,1,`) + len64(`{"foo":"bar","fizz":[0,`),
//		JSONPointer: "/1/alpha/2" + "/fizz/1",
//		GoType:      reflect.TypeFor[innerType](),
//		Err:         ...,
//	}
//
// This is used to annotate errors returned by user-provided
// v1 MarshalJSON or UnmarshalJSON methods with precise position information
// if they themselves happened to return a SemanticError.
// Since MarshalJSON and UnmarshalJSON are not operating on the root JSON value,
// their positioning must be relative to the nested JSON value
// returned by UnmarshalJSON or passed to MarshalJSON.
// Therefore, we can construct an absolute position by concatenating
// the outer with the inner positions.
//
// Note that we do not use collapseSemanticErrors with user-provided functions
// that take in an [jsontext.Encoder] or [jsontext.Decoder] since they contain
// methods to report position relative to the root JSON value.
// We assume user-constructed errors are correctly precise about position.
func collapseSemanticErrors(err error) error {
	if serr1, ok := err.(*SemanticError); ok {
		if serr2, ok := serr1.Err.(*SemanticError); ok {
			serr2.ByteOffset = serr1.ByteOffset + serr2.ByteOffset
			serr2.JSONPointer = serr1.JSONPointer + serr2.JSONPointer
			*serr1 = *serr2
		}
	}
	return err
}

// errorModalVerb is a modal verb like "cannot" or "unable to".
//
// Once per process, Hyrum-proof the error message by deliberately
// switching between equivalent renderings of the same error message.
// The randomization is tied to the Hyrum-proofing already applied
// on map iteration in Go.
var errorModalVerb = sync.OnceValue(func() string {
	for phrase := range map[string]struct{}{"cannot": {}, "unable to": {}} {
		return phrase // use whichever phrase we get in the first iteration
	}
	return ""
})

func (e *SemanticError) Error() string {
	var sb strings.Builder
	sb.WriteString(errorPrefix)
	sb.WriteString(errorModalVerb())

	// Format action.
	var preposition string
	switch e.action {
	case "marshal":
		sb.WriteString(" marshal")
		preposition = " from"
	case "unmarshal":
		sb.WriteString(" unmarshal")
		preposition = " into"
	default:
		sb.WriteString(" handle")
		preposition = " with"
	}

	// Format JSON kind.
	switch e.JSONKind {
	case 'n':
		sb.WriteString(" JSON null")
	case 'f', 't':
		sb.WriteString(" JSON boolean")
	case '"':
		sb.WriteString(" JSON string")
	case '0':
		sb.WriteString(" JSON number")
	case '{', '}':
		sb.WriteString(" JSON object")
	case '[', ']':
		sb.WriteString(" JSON array")
	default:
		if e.action == "" {
			preposition = ""
		}
	}
	if len(e.JSONValue) > 0 && len(e.JSONValue) < 100 {
		sb.WriteByte(' ')
		sb.Write(e.JSONValue)
	}

	// Format Go type.
	if e.GoType != nil {
		typeString := e.GoType.String()
		if len(typeString) > 100 {
			// An excessively long type string most likely occurs for
			// an anonymous struct declaration with many fields.
			// Reduce the noise by just printing the kind,
			// and optionally prepending it with the package name
			// if the struct happens to include an unexported field.
			typeString = e.GoType.Kind().String()
			if e.GoType.Kind() == reflect.Struct && e.GoType.Name() == "" {
				for i := range e.GoType.NumField() {
					if pkgPath := e.GoType.Field(i).PkgPath; pkgPath != "" {
						typeString = pkgPath[strings.LastIndexByte(pkgPath, '/')+len("/"):] + ".struct"
						break
					}
				}
			}
		}
		sb.WriteString(preposition)
		sb.WriteString(" Go ")
		sb.WriteString(typeString)
	}

	// Special handling for unknown names.
	if e.Err == ErrUnknownName {
		sb.WriteString(": ")
		sb.WriteString(ErrUnknownName.Error())
		sb.WriteString(" ")
		sb.WriteString(strconv.Quote(e.JSONPointer.LastToken()))
		if parent := e.JSONPointer.Parent(); parent != "" {
			sb.WriteString(" within ")
			sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(parent), 100)))
		}
		return sb.String()
	}

	// Format where.
	// Avoid printing if it overlaps with a wrapped SyntacticError.
	switch serr, _ := e.Err.(*jsontext.SyntacticError); {
	case e.JSONPointer != "":
		if serr == nil || !e.JSONPointer.Contains(serr.JSONPointer) {
			sb.WriteString(" within ")
			sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(e.JSONPointer), 100)))
		}
	case e.ByteOffset > 0:
		if serr == nil || !(e.ByteOffset <= serr.ByteOffset) {
			sb.WriteString(" after offset ")
			sb.WriteString(strconv.FormatInt(e.ByteOffset, 10))
		}
	}

	// Format underlying error.
	if e.Err != nil {
		errString := e.Err.Error()
		if isSyntacticError(e.Err) {
			errString = strings.TrimPrefix(errString, "jsontext: ")
		}
		sb.WriteString(": ")
		sb.WriteString(errString)
	}

	return sb.String()
}

func (e *SemanticError) Unwrap() error {
	return e.Err
}

func newDuplicateNameError(ptr jsontext.Pointer, quotedName []byte, offset int64) error {
	if quotedName != nil {
		name, _ := jsonwire.AppendUnquote(nil, quotedName)
		ptr = ptr.AppendToken(string(name))
	}
	return &jsontext.SyntacticError{
		ByteOffset:  offset,
		JSONPointer: ptr,
		Err:         jsontext.ErrDuplicateName,
	}
}

// toUnexpectedEOF converts [io.EOF] to [io.ErrUnexpectedEOF].
func toUnexpectedEOF(err error) error {
	if err == io.EOF {
		return io.ErrUnexpectedEOF
	}
	return err
}
