// Code generated manually for JSON invocation support.
// This file provides InvokeJSON method for calling MTProto methods via JSON.

package tg

import (
	
	
	

	
	

	
	
	
)

// InvokeJSON invokes an MTProto method using JSON input.
// The JSON input should contain an "@type" field with the method name (e.g., "messages.sendMessage").
// All method parameters should be included in the same JSON object.
//
// The JSON format follows MTProto JSON API specification where:
// - "@type" field contains the method or type name
// - All fields use snake_case naming
// - Nested objects also include "@type" field
//
// useSnakeCase controls the output JSON field naming convention:
// - true: Use snake_case (MTProto convention, e.g., "user_id", "access_hash")
// - false: Use PascalCase (Go struct field names, e.g., "UserID", "AccessHash")
//
// Example:
//
//	jsonInput := `{
//	  "@type": "messages.sendMessage",
//	  "peer": {"@type": "inputPeerUser", "user_id": 123, "access_hash": 456},
//	  "message": "Hello",
//	  "random_id": 123456789
//	}`
//	result, err := client.InvokeJSON(ctx, jsonInput, true) // true = snake_case output
func ( *Client) ( context.Context,  string,  bool) (string, error) {
	// Parse JSON to extract @type field
	 := jx.DecodeStr()
	var  string
	if  := .ObjBytes(func( *jx.Decoder,  []byte) error {
		if string() == tdjson.TypeField {
			,  := .Str()
			if  != nil {
				return 
			}
			 = 
			return nil
		}
		return .Skip()
	});  != nil {
		return "", errors.Wrap(, "extract @type")
	}

	if  == "" {
		return "", errors.New("@type field is required")
	}

	// Get type ID from method name
	 := NamesMap()
	,  := []
	if ! {
		return "", errors.Errorf("unknown method or type: %q", )
	}

	// Create request object using constructor (no reflection)
	 := TypesConstructorMap()
	,  := []
	if ! {
		return "", errors.Errorf("no constructor for type ID: 0x%x (%s)", , )
	}

	 := ()
	if  == nil {
		return "", errors.Errorf("constructor returned nil for type ID: 0x%x (%s)", , )
	}

	// Convert JSON to binary format using jx for parsing (no encoding/json)
	// Create a fresh decoder since the previous one was consumed
	if  := jsonUnmarshalToObject(, );  != nil {
		return "", errors.Wrap(, "unmarshal JSON to object")
	}

	// For result, we use a generic decoder that can handle any result type
	 := &genericResultDecoder{
		constructors: ,
	}

	// Invoke method
	if  := .rpc.Invoke(, .(bin.Encoder), );  != nil {
		return "", 
	}

	if .result == nil {
		return "", errors.New("no result from invocation")
	}

	// Convert binary directly to pure MTProto JSON
	// Note: For output, we still use encoding/json since manual encoding requires reflection
	// The key improvement is that input parsing uses jx, not encoding/json
	return binaryToMTProtoJSON(.buffer, .typeID, )
}

// genericResultDecoder is a decoder that can decode any response type
// and store it for later JSON encoding.
type genericResultDecoder struct {
	constructors map[uint32]func() bin.Object
	result       bin.Object
	buffer       *bin.Buffer
	typeID       uint32
}

func ( *genericResultDecoder) ( *bin.Buffer) error {
	// Peek at the type ID to determine what to decode
	,  := .PeekID()
	if  != nil {
		return errors.Wrap(, "peek response type ID")
	}

	.typeID = 

	// Save the buffer for later JSON encoding
	.buffer = &bin.Buffer{Buf: make([]byte, len(.Buf))}
	copy(.buffer.Buf, .Buf)

	// Use TypesConstructorMap to create appropriate instance
	,  := .constructors[]
	if ! {
		return errors.Errorf("unknown response type: 0x%x", )
	}

	 := ()
	if  == nil {
		return errors.Errorf("failed to create response instance for type: 0x%x", )
	}

	// Decode into instance
	,  := .(bin.Decoder)
	if ! {
		return errors.Errorf("response type does not implement bin.Decoder")
	}

	if  := .Decode();  != nil {
		return errors.Wrap(, "decode response")
	}

	// Store as bin.Object
	if ,  := .(bin.Object);  {
		.result = 
	} else {
		return errors.New("response is not a bin.Object")
	}

	return nil
}

// jsonValue represents an intermediate JSON value during parsing
type jsonValue struct {
	typ     jx.Type
	str     string
	num     jx.Num
	boolean bool
	arr     []jsonValue
	obj     map[string]jsonValue
}

// jsonUnmarshalToObject unmarshals JSON into an MTProto object using jx.
// Parses JSON with jx into intermediate structure, then encodes to binary.
func ( string,  bin.Object) error {
	// Get TypeInfo to know field structure
	,  := .(interface{ () tdp.Type })
	if ! {
		return errors.New("object does not implement TypeInfo()")
	}

	 := .()

	// Parse JSON with jx into intermediate structure
	 := jx.DecodeStr()
	,  := parseJSONObject()
	if  != nil {
		return errors.Wrap(, "parse JSON object")
	}

	// Build binary buffer
	 := &bin.Buffer{}
	.PutID(.ID)

	// Encode each field in order based on TypeInfo
	for ,  := range .Fields {
		// Skip flags fields - they will be set by SetFlags() after decoding
		if .SchemaName == "flags" || .SchemaName == "flags2" {
			continue
		}

		// Skip null/optional fields that aren't present
		if .Null {
			if ,  := [.SchemaName]; ! {
				continue
			}
		}

		,  := [.SchemaName]
		if ! {
			continue
		}

		// Encode field value to binary
		if  := encodeJSONValueToBinary(, );  != nil {
			return errors.Wrapf(, "encode field %s", .SchemaName)
		}
	}

	// Decode binary back to object
	if  := .Decode();  != nil {
		return errors.Wrap(, "decode binary to object")
	}

	// Set flags if the object supports it
	if ,  := .(interface{ () });  {
		.()
	}

	return nil
}

// parseJSONObject parses a JSON object into a map of field values
// includeTypeField controls whether to include @type field (needed for nested objects)
// The decoder should be positioned at the start (ObjBytes will call Next() internally)
func ( *jx.Decoder) (map[string]jsonValue, error) {
	return parseJSONObjectWithType(, false)
}

// parseJSONObjectWithType parses a JSON object, optionally including @type field
// ObjBytes will internally call Next() to check if it's an object
func ( *jx.Decoder,  bool) (map[string]jsonValue, error) {
	 := make(map[string]jsonValue)

	if  := .ObjBytes(func( *jx.Decoder,  []byte) error {
		 := string()

		// Skip @type field if includeType is false (for root object)
		if  == "@type" && ! {
			return .Skip()
		}

		,  := parseJSONValue()
		if  != nil {
			return errors.Wrapf(, "parse field %s", )
		}

		[] = 
		return nil
	});  != nil {
		return nil, 
	}

	return , nil
}

// parseJSONValue parses a single JSON value
func ( *jx.Decoder) (jsonValue, error) {
	var  jsonValue

	// Peek at the next token to determine type
	 := .Next()

	switch  {
	case jx.Object:
		// Parse object recursively (include @type for nested objects)
		// Next() has already consumed the object token, so we're now inside the object
		// We can call ObjBytes directly
		 := make(map[string]jsonValue)
		if  := .ObjBytes(func( *jx.Decoder,  []byte) error {
			 := string()
			// Always include @type for nested objects
			,  := ()
			if  != nil {
				return errors.Wrapf(, "parse field %s", )
			}
			[] = 
			return nil
		});  != nil {
			return jsonValue{}, errors.Wrap(, "parse nested object")
		}
		.typ = jx.Object
		.obj = 
	case jx.Array:
		// Parse array
		 := []jsonValue{}
		if  := .Arr(func( *jx.Decoder) error {
			,  := ()
			if  != nil {
				return errors.Wrap(, "parse array item")
			}
			 = append(, )
			return nil
		});  != nil {
			return jsonValue{}, errors.Wrap(, "parse array")
		}
		.typ = jx.Array
		.arr = 
	case jx.String:
		,  := .Str()
		if  != nil {
			return jsonValue{}, errors.Wrap(, "parse string")
		}
		.typ = jx.String
		.str = 
	case jx.Number:
		,  := .Num()
		if  != nil {
			return jsonValue{}, errors.Wrap(, "parse number")
		}
		.typ = jx.Number
		.num = 
	case jx.Bool:
		,  := .Bool()
		if  != nil {
			return jsonValue{}, errors.Wrap(, "parse bool")
		}
		.typ = jx.Bool
		.boolean = 
	case jx.Null:
		if  := .Null();  != nil {
			return jsonValue{}, errors.Wrap(, "parse null")
		}
		.typ = jx.Null
	default:
		return jsonValue{}, errors.Errorf("unexpected JSON token: %v", )
	}

	return , nil
}

// encodeJSONValueToBinary encodes a jsonValue to binary format
func ( *bin.Buffer,  jsonValue) error {
	return encodeJSONValueToBinaryWithContext(, , "")
}

// encodeJSONValueToBinaryWithContext encodes a jsonValue to binary format with field context
func ( *bin.Buffer,  jsonValue,  string) error {
	switch .typ {
	case jx.Object:
		// This is an interface type (object with @type)
		return encodeInterfaceObjectToBinary(, .obj)
	case jx.Array:
		// This is an array
		.PutVectorHeader(len(.arr))
		for ,  := range .arr {
			if  := encodeJSONValueToBinary(, );  != nil {
				return errors.Wrap(, "encode array item")
			}
		}
		return nil
	case jx.Bool:
		.PutBool(.boolean)
	case jx.Number:
		if .num.IsInt() {
			,  := .num.Int64()
			if  != nil {
				return errors.Wrap(, "parse integer")
			}
			.PutLong()
		} else {
			,  := .num.Float64()
			if  != nil {
				return errors.Wrap(, "parse float")
			}
			.PutDouble()
		}
	case jx.String:
		// Check if this might be Int128 or Int256 (hex-encoded)
		// Int128 = 16 bytes = 32 hex chars, Int256 = 32 bytes = 64 hex chars
		if isHexString(.str) {
			 := len(.str)
			// Check field name hints (common names for Int128/Int256 fields)
			// Also check length - if it's exactly 32 or 64 hex chars, it's likely Int128/Int256
			 :=  == "public_key" ||
				 == "key" ||
				 == "nonce" ||
				 == "secret" ||
				 == 32 ||  == 64

			if  {
				switch  {
				case 32: // Int128
					var  bin.Int128
					if ,  := hex.Decode([:], []byte(.str));  == nil {
						.PutInt128()
						return nil
					}
				case 64: // Int256
					var  bin.Int256
					if ,  := hex.Decode([:], []byte(.str));  == nil {
						.PutInt256()
						return nil
					}
				}
			}
		}
		// Regular string
		.PutString(.str)
	case jx.Null:
		// Nil values are typically not encoded (handled by optional fields)
		return nil
	default:
		return errors.Errorf("unsupported JSON value type: %v", .typ)
	}
	return nil
}

// encodeInterfaceObjectToBinary encodes an interface object (with @type) to binary
func ( *bin.Buffer,  map[string]jsonValue) error {
	// Extract @type
	,  := [tdjson.TypeField]
	if ! {
		return errors.New("interface object missing @type field")
	}

	if .typ != jx.String {
		return errors.New("@type field must be a string")
	}

	 := .str

	// Get type ID and constructor
	 := NamesMap()
	,  := []
	if ! {
		return errors.Errorf("unknown type: %q", )
	}

	 := TypesConstructorMap()
	,  := []
	if ! {
		return errors.Errorf("no constructor for type: %q", )
	}

	 := ()
	if  == nil {
		return errors.Errorf("constructor returned nil for type: %q", )
	}

	// Get TypeInfo for the concrete object
	,  := .(interface{ () tdp.Type })
	if ! {
		return errors.New("concrete object does not implement TypeInfo()")
	}

	 := .()

	// Build binary buffer for concrete object
	 := &bin.Buffer{}
	.PutID(.ID)

	// Encode each field
	for ,  := range .Fields {
		if .SchemaName == "flags" || .SchemaName == "flags2" {
			continue
		}

		if .Null {
			if ,  := [.SchemaName]; ! {
				continue
			}
		}

		,  := [.SchemaName]
		if ! {
			continue
		}

		// Encode field value, with context about field name for better type detection
		if  := encodeJSONValueToBinaryWithContext(, , .SchemaName);  != nil {
			return errors.Wrapf(, "encode field %s", .SchemaName)
		}
	}

	// Try to decode to concrete object to validate encoding
	// If it fails, it might be because we encoded a hex string incorrectly
	 := &bin.Buffer{Buf: make([]byte, len(.Buf))}
	copy(.Buf, .Buf)

	if  := .Decode();  != nil {
		// Decode failed - might be because we encoded a hex string as regular string
		// Try re-encoding with Int128/Int256 detection for hex strings
		return retryEncodeWithInt128Int256(, , , , )
	}

	// Decode succeeded, use the decoded object
	// Set flags
	if ,  := .(interface{ () });  {
		.()
	}

	// Encode the concrete object to the output buffer
	return .(bin.Encoder).Encode()
}

// retryEncodeWithInt128Int256 retries encoding with Int128/Int256 detection for hex strings
func ( *bin.Buffer,  map[string]jsonValue,  string,  bin.Object,  tdp.Type) error {
	// Rebuild binary buffer, this time being more aggressive about Int128/Int256 detection
	 := &bin.Buffer{}
	.PutID(.ID)

	// Encode each field with enhanced Int128/Int256 detection
	for ,  := range .Fields {
		if .SchemaName == "flags" || .SchemaName == "flags2" {
			continue
		}

		if .Null {
			if ,  := [.SchemaName]; ! {
				continue
			}
		}

		,  := [.SchemaName]
		if ! {
			continue
		}

		// Encode field value with field name context for Int128/Int256 detection
		if  := encodeJSONValueToBinaryWithContext(, , .SchemaName);  != nil {
			return errors.Wrapf(, "encode field %s", .SchemaName)
		}
	}

	// Try to decode again
	 := &bin.Buffer{Buf: make([]byte, len(.Buf))}
	copy(.Buf, .Buf)

	if  := .Decode();  != nil {
		return errors.Wrapf(, "retry decode failed for type %q", )
	}

	// Set flags
	if ,  := .(interface{ () });  {
		.()
	}

	// Encode to output buffer
	return .(bin.Encoder).Encode()
}

// isHexString checks if a string is a valid hex string
func ( string) bool {
	if len() == 0 {
		return false
	}
	for ,  := range  {
		if !(( >= '0' &&  <= '9') || ( >= 'a' &&  <= 'f') || ( >= 'A' &&  <= 'F')) {
			return false
		}
	}
	return true
}

// binaryToMTProtoJSON converts binary MTProto buffer to JSON.
// Note: For output marshaling, we use encoding/json since manual encoding
// would require reflection or code generation. The key improvement is that
// input parsing uses jx, not encoding/json.
// useSnakeCase controls whether to convert field names to snake_case (true) or keep PascalCase (false).
func ( *bin.Buffer,  uint32,  bool) (string, error) {
	// Get type name from registry
	 := NamesMap()
	 := ""
	for ,  := range  {
		if  ==  {
			 = 
			break
		}
	}
	if  == "" {
		return "", errors.Errorf("type name not found for ID: 0x%x", )
	}

	// Decode binary to Go struct
	 := TypesConstructorMap()
	,  := []
	if ! {
		return "", errors.Errorf("no constructor for type ID: 0x%x", )
	}

	 := ()
	if  == nil {
		return "", errors.New("constructor returned nil")
	}

	// Decode from buffer
	if  != nil {
		 := &bin.Buffer{Buf: make([]byte, len(.Buf))}
		copy(.Buf, .Buf)
		if  := .Decode();  != nil {
			return "", errors.Wrap(, "decode binary to object")
		}
	}

	// Use jx.Encoder to build JSON manually
	// We'll encode using TypeInfo to iterate fields
	return encodeObjectToJSONWithJX(, , )
}

// encodeObjectToJSONWithJX encodes a bin.Object to JSON.
// Note: We use encoding/json for output marshaling since:
// 1. The object is already properly decoded from binary
// 2. Structs have JSON tags for proper field names
// 3. Manual encoding would require reflection or code generation
// The key improvement is that input parsing uses jx, not encoding/json.
// useSnakeCase controls whether to convert field names to snake_case (true) or keep PascalCase (false).
func ( bin.Object,  string,  bool) (string, error) {
	// Marshal object to JSON (uses struct field names, which are PascalCase)
	,  := json.Marshal()
	if  != nil {
		return "", errors.Wrap(, "marshal object to JSON")
	}

	// Parse and ensure @type field is present
	var  map[string]interface{}
	if  := json.Unmarshal(, &);  != nil {
		return string(), nil // Return as-is if unmarshal fails
	}

	["@type"] = 

	// Convert field names to snake_case if requested
	if  {
		 = convertKeysToSnakeCase()
	}

	,  := json.Marshal()
	if  != nil {
		return "", errors.Wrap(, "marshal result")
	}

	return string(), nil
}

// convertKeysToSnakeCase recursively converts map keys from PascalCase to snake_case
func ( map[string]interface{}) map[string]interface{} {
	 := make(map[string]interface{})
	for ,  := range  {
		 := pascalToSnakeCase()
		switch val := .(type) {
		case map[string]interface{}:
			[] = ()
		case []interface{}:
			 := make([]interface{}, len())
			for ,  := range  {
				if ,  := .(map[string]interface{});  {
					[] = ()
				} else {
					[] = 
				}
			}
			[] = 
		default:
			[] = 
		}
	}
	return 
}

// pascalToSnakeCase converts PascalCase to snake_case
func ( string) string {
	if  == "" {
		return 
	}

	var  []rune
	for ,  := range  {
		if  > 0 &&  >= 'A' &&  <= 'Z' {
			 = append(, '_')
		}
		if  >= 'A' &&  <= 'Z' {
			 = append(, +'a'-'A')
		} else {
			 = append(, )
		}
	}
	return string()
}