package pgtype

import (
	
	
	
	
	
)

type JSONCodec struct{}

func (JSONCodec) ( int16) bool {
	return  == TextFormatCode ||  == BinaryFormatCode
}

func (JSONCodec) () int16 {
	return TextFormatCode
}

func ( JSONCodec) ( *Map,  uint32,  int16,  any) EncodePlan {
	switch .(type) {
	case string:
		return encodePlanJSONCodecEitherFormatString{}
	case []byte:
		return encodePlanJSONCodecEitherFormatByteSlice{}

	// Must come before trying wrap encode plans because a pointer to a struct may be unwrapped to a struct that can be
	// marshalled.
	//
	// https://github.com/jackc/pgx/issues/1681
	case json.Marshaler:
		return encodePlanJSONCodecEitherFormatMarshal{}

	// Cannot rely on driver.Valuer being handled later because anything can be marshalled.
	//
	// https://github.com/jackc/pgx/issues/1430
	case driver.Valuer:
		return &encodePlanDriverValuer{m: , oid: , formatCode: }
	}

	// Because anything can be marshalled the normal wrapping in Map.PlanScan doesn't get a chance to run. So try the
	// appropriate wrappers here.
	for ,  := range []TryWrapEncodePlanFunc{
		TryWrapDerefPointerEncodePlan,
		TryWrapFindUnderlyingTypeEncodePlan,
	} {
		if , ,  := ();  {
			if  := .(, , , );  != nil {
				.SetNext()
				return 
			}
		}
	}

	return encodePlanJSONCodecEitherFormatMarshal{}
}

type encodePlanJSONCodecEitherFormatString struct{}

func (encodePlanJSONCodecEitherFormatString) ( any,  []byte) ( []byte,  error) {
	 := .(string)
	 = append(, ...)
	return , nil
}

type encodePlanJSONCodecEitherFormatByteSlice struct{}

func (encodePlanJSONCodecEitherFormatByteSlice) ( any,  []byte) ( []byte,  error) {
	 := .([]byte)
	if  == nil {
		return nil, nil
	}

	 = append(, ...)
	return , nil
}

type encodePlanJSONCodecEitherFormatMarshal struct{}

func (encodePlanJSONCodecEitherFormatMarshal) ( any,  []byte) ( []byte,  error) {
	,  := json.Marshal()
	if  != nil {
		return nil, 
	}

	 = append(, ...)
	return , nil
}

func (JSONCodec) ( *Map,  uint32,  int16,  any) ScanPlan {
	switch .(type) {
	case *string:
		return scanPlanAnyToString{}

	case **string:
		// This is to fix **string scanning. It seems wrong to special case **string, but it's not clear what a better
		// solution would be.
		//
		// https://github.com/jackc/pgx/issues/1470 -- **string
		// https://github.com/jackc/pgx/issues/1691 -- ** anything else

		if , ,  := TryPointerPointerScanPlan();  {
			if  := .planScan(, , );  != nil {
				if ,  := .(*scanPlanFail); ! {
					.SetNext()
					return 
				}
			}
		}

	case *[]byte:
		return scanPlanJSONToByteSlice{}
	case BytesScanner:
		return scanPlanBinaryBytesToBytesScanner{}

	// Cannot rely on sql.Scanner being handled later because scanPlanJSONToJSONUnmarshal will take precedence.
	//
	// https://github.com/jackc/pgx/issues/1418
	case sql.Scanner:
		return &scanPlanSQLScanner{formatCode: }
	}

	return scanPlanJSONToJSONUnmarshal{}
}

type scanPlanAnyToString struct{}

func (scanPlanAnyToString) ( []byte,  any) error {
	 := .(*string)
	* = string()
	return nil
}

type scanPlanJSONToByteSlice struct{}

func (scanPlanJSONToByteSlice) ( []byte,  any) error {
	 := .(*[]byte)
	if  == nil {
		* = nil
		return nil
	}

	* = make([]byte, len())
	copy(*, )
	return nil
}

type scanPlanJSONToBytesScanner struct{}

func (scanPlanJSONToBytesScanner) ( []byte,  any) error {
	 := ().(BytesScanner)
	return .ScanBytes()
}

type scanPlanJSONToJSONUnmarshal struct{}

func (scanPlanJSONToJSONUnmarshal) ( []byte,  any) error {
	if  == nil {
		 := reflect.ValueOf()
		if .Kind() == reflect.Ptr {
			 := .Elem()
			switch .Kind() {
			case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface:
				.Set(reflect.Zero(.Type()))
				return nil
			}
		}

		return fmt.Errorf("cannot scan NULL into %T", )
	}

	 := reflect.ValueOf().Elem()
	.Set(reflect.Zero(.Type()))

	return json.Unmarshal(, )
}

func ( JSONCodec) ( *Map,  uint32,  int16,  []byte) (driver.Value, error) {
	if  == nil {
		return nil, nil
	}

	 := make([]byte, len())
	copy(, )
	return , nil
}

func ( JSONCodec) ( *Map,  uint32,  int16,  []byte) (any, error) {
	if  == nil {
		return nil, nil
	}

	var  any
	 := json.Unmarshal(, &)
	return , 
}