// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 extensions

import (
	
	
	

	
	
	
	
)

var jsonSupportedStorageTypes = []arrow.DataType{
	arrow.BinaryTypes.String,
	arrow.BinaryTypes.LargeString,
	arrow.BinaryTypes.StringView,
}

// JSONType represents a UTF-8 encoded JSON string as specified in RFC8259.
type JSONType struct {
	arrow.ExtensionBase
}

// ParquetLogicalType implements pqarrow.ExtensionCustomParquetType.
func ( *JSONType) () schema.LogicalType {
	return schema.JSONLogicalType{}
}

// NewJSONType creates a new JSONType with the specified storage type.
// storageType must be one of String, LargeString, StringView.
func ( arrow.DataType) (*JSONType, error) {
	if !slices.Contains(jsonSupportedStorageTypes, ) {
		return nil, fmt.Errorf("unsupported storage type for JSON extension type: %s", )
	}
	return &JSONType{ExtensionBase: arrow.ExtensionBase{Storage: }}, nil
}

func ( *JSONType) () reflect.Type { return reflect.TypeOf(JSONArray{}) }

func ( *JSONType) ( arrow.DataType,  string) (arrow.ExtensionType, error) {
	if  != "" &&  != "{}" {
		return nil, fmt.Errorf("serialized metadata for JSON extension type must be '' or '{}', found: %s", )
	}
	return NewJSONType()
}

func ( *JSONType) ( arrow.ExtensionType) bool {
	return .ExtensionName() == .ExtensionName() && arrow.TypeEqual(.Storage, .StorageType())
}

func ( *JSONType) () string { return "arrow.json" }

func ( *JSONType) () string { return "" }

func ( *JSONType) () string {
	return fmt.Sprintf("extension<%s[storage_type=%s]>", .ExtensionName(), .Storage)
}

// JSONArray is logically an array of UTF-8 encoded JSON strings.
// Its values are unmarshaled to native Go values.
type JSONArray struct {
	array.ExtensionArrayBase
}

func ( *JSONArray) () string {
	,  := .MarshalJSON()
	if  != nil {
		panic(fmt.Sprintf("failed marshal JSONArray: %s", ))
	}

	return string()
}

func ( *JSONArray) ( int) any {
	 := .ValueBytes()

	var  any
	if  := json.Unmarshal(, &);  != nil {
		panic()
	}

	return 
}

func ( *JSONArray) ( int) string {
	return string(.ValueBytes())
}

func ( *JSONArray) ( int) []byte {
	// convert to json.RawMessage, set to nil if elem isNull.
	 := .ValueJSON()

	// simply returns wrapped bytes, or null if val is nil.
	,  := .MarshalJSON()
	if  != nil {
		panic()
	}

	return 
}

// ValueJSON wraps the underlying string value as a json.RawMessage,
// or returns nil if the array value is null.
func ( *JSONArray) ( int) json.RawMessage {
	var  json.RawMessage
	if .IsValid() {
		 = json.RawMessage(.Storage().(array.StringLike).Value())
	}
	return 
}

// MarshalJSON implements json.Marshaler.
// Marshaling json.RawMessage is a no-op, except that nil values will
// be marshaled as a JSON null.
func ( *JSONArray) () ([]byte, error) {
	 := make([]json.RawMessage, .Len())
	for  := 0;  < .Len(); ++ {
		[] = .ValueJSON()
	}
	return json.Marshal()
}

// GetOneForMarshal implements arrow.Array.
func ( *JSONArray) ( int) interface{} {
	return .ValueJSON()
}

var (
	_ arrow.ExtensionType  = (*JSONType)(nil)
	_ array.ExtensionArray = (*JSONArray)(nil)
)