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

// This file implements JSON Pointers.
// A JSON Pointer is a path that refers to one JSON value within another.
// If the path is empty, it refers to the root value.
// Otherwise, it is a sequence of slash-prefixed strings, like "/points/1/x",
// selecting successive properties (for JSON objects) or items (for JSON arrays).
// For example, when applied to this JSON value:
//    {
// 	     "points": [
// 	 	    {"x": 1, "y": 2},
// 	 	    {"x": 3, "y": 4}
// 		 ]
//    }
//
// the JSON Pointer "/points/1/x" refers to the number 3.
// See the spec at https://datatracker.ietf.org/doc/html/rfc6901.

package jsonschema

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"golang.org/x/tools/internal/mcp/internal/util"
)

var (
	jsonPointerEscaper   = strings.NewReplacer("~", "~0", "/", "~1")
	jsonPointerUnescaper = strings.NewReplacer("~0", "~", "~1", "/")
)

func escapeJSONPointerSegment(s string) string {
	return jsonPointerEscaper.Replace(s)
}

func unescapeJSONPointerSegment(s string) string {
	return jsonPointerUnescaper.Replace(s)
}

// parseJSONPointer splits a JSON Pointer into a sequence of segments. It doesn't
// convert strings to numbers, because that depends on the traversal: a segment
// is treated as a number when applied to an array, but a string when applied to
// an object. See section 4 of the spec.
func parseJSONPointer(ptr string) (segments []string, err error) {
	if ptr == "" {
		return nil, nil
	}
	if ptr[0] != '/' {
		return nil, fmt.Errorf("JSON Pointer %q does not begin with '/'", ptr)
	}
	// Unlike file paths, consecutive slashes are not coalesced.
	// Split is nicer than Cut here, because it gets a final "/" right.
	segments = strings.Split(ptr[1:], "/")
	if strings.Contains(ptr, "~") {
		// Undo the simple escaping rules that allow one to include a slash in a segment.
		for i := range segments {
			segments[i] = unescapeJSONPointerSegment(segments[i])
		}
	}
	return segments, nil
}

// dereferenceJSONPointer returns the Schema that sptr points to within s,
// or an error if none.
// This implementation suffices for JSON Schema: pointers are applied only to Schemas,
// and refer only to Schemas.
func dereferenceJSONPointer(s *Schema, sptr string) (_ *Schema, err error) {
	defer util.Wrapf(&err, "JSON Pointer %q", sptr)

	segments, err := parseJSONPointer(sptr)
	if err != nil {
		return nil, err
	}
	v := reflect.ValueOf(s)
	for _, seg := range segments {
		switch v.Kind() {
		case reflect.Pointer:
			v = v.Elem()
			if !v.IsValid() {
				return nil, errors.New("navigated to nil reference")
			}
			fallthrough // if valid, can only be a pointer to a Schema

		case reflect.Struct:
			// The segment must refer to a field in a Schema.
			if v.Type() != reflect.TypeFor[Schema]() {
				return nil, fmt.Errorf("navigated to non-Schema %s", v.Type())
			}
			v = lookupSchemaField(v, seg)
			if !v.IsValid() {
				return nil, fmt.Errorf("no schema field %q", seg)
			}
		case reflect.Slice, reflect.Array:
			// The segment must be an integer without leading zeroes that refers to an item in the
			// slice or array.
			if seg == "-" {
				return nil, errors.New("the JSON Pointer array segment '-' is not supported")
			}
			if len(seg) > 1 && seg[0] == '0' {
				return nil, fmt.Errorf("segment %q has leading zeroes", seg)
			}
			n, err := strconv.Atoi(seg)
			if err != nil {
				return nil, fmt.Errorf("invalid int: %q", seg)
			}
			if n < 0 || n >= v.Len() {
				return nil, fmt.Errorf("index %d is out of bounds for array of length %d", n, v.Len())
			}
			v = v.Index(n)
			// Cannot be invalid.
		case reflect.Map:
			// The segment must be a key in the map.
			v = v.MapIndex(reflect.ValueOf(seg))
			if !v.IsValid() {
				return nil, fmt.Errorf("no key %q in map", seg)
			}
		default:
			return nil, fmt.Errorf("value %s (%s) is not a schema, slice or map", v, v.Type())
		}
	}
	if s, ok := v.Interface().(*Schema); ok {
		return s, nil
	}
	return nil, fmt.Errorf("does not refer to a schema, but to a %s", v.Type())
}

// lookupSchemaField returns the value of the field with the given name in v,
// or the zero value if there is no such field or it is not of type Schema or *Schema.
func lookupSchemaField(v reflect.Value, name string) reflect.Value {
	if name == "type" {
		// The "type" keyword may refer to Type or Types.
		// At most one will be non-zero.
		if t := v.FieldByName("Type"); !t.IsZero() {
			return t
		}
		return v.FieldByName("Types")
	}
	if sf, ok := schemaFieldMap[name]; ok {
		return v.FieldByIndex(sf.Index)
	}
	return reflect.Value{}
}
