package pgx

import (
	

	
	
)

// ExtendedQueryBuilder is used to choose the parameter formats, to format the parameters and to choose the result
// formats for an extended query.
type ExtendedQueryBuilder struct {
	ParamValues     [][]byte
	paramValueBytes []byte
	ParamFormats    []int16
	ResultFormats   []int16
}

// Build sets ParamValues, ParamFormats, and ResultFormats for use with *PgConn.ExecParams or *PgConn.ExecPrepared. If
// sd is nil then QueryExecModeExec behavior will be used.
func ( *ExtendedQueryBuilder) ( *pgtype.Map,  *pgconn.StatementDescription,  []any) error {
	.reset()

	if  == nil {
		for  := range  {
			 := .appendParam(, 0, pgtype.TextFormatCode, [])
			if  != nil {
				 = fmt.Errorf("failed to encode args[%d]: %w", , )
				return 
			}
		}
		return nil
	}

	if len(.ParamOIDs) != len() {
		return fmt.Errorf("mismatched param and argument count")
	}

	for  := range  {
		 := .appendParam(, .ParamOIDs[], -1, [])
		if  != nil {
			 = fmt.Errorf("failed to encode args[%d]: %w", , )
			return 
		}
	}

	for  := range .Fields {
		.appendResultFormat(.FormatCodeForOID(.Fields[].DataTypeOID))
	}

	return nil
}

// appendParam appends a parameter to the query. format may be -1 to automatically choose the format. If arg is nil it
// must be an untyped nil.
func ( *ExtendedQueryBuilder) ( *pgtype.Map,  uint32,  int16,  any) error {
	if  == -1 {
		 := .chooseParameterFormatCode(, , )
		 := .(, , , )
		if  == nil {
			return nil
		}

		var  int16
		if  == TextFormatCode {
			 = BinaryFormatCode
		} else {
			 = TextFormatCode
		}

		 := .(, , , )
		if  == nil {
			return nil
		}

		return  // return the error from the preferred format
	}

	,  := .encodeExtendedParamValue(, , , )
	if  != nil {
		return 
	}

	.ParamFormats = append(.ParamFormats, )
	.ParamValues = append(.ParamValues, )

	return nil
}

// appendResultFormat appends a result format to the query.
func ( *ExtendedQueryBuilder) ( int16) {
	.ResultFormats = append(.ResultFormats, )
}

// reset readies eqb to build another query.
func ( *ExtendedQueryBuilder) () {
	.ParamValues = .ParamValues[0:0]
	.paramValueBytes = .paramValueBytes[0:0]
	.ParamFormats = .ParamFormats[0:0]
	.ResultFormats = .ResultFormats[0:0]

	if cap(.ParamValues) > 64 {
		.ParamValues = make([][]byte, 0, 64)
	}

	if cap(.paramValueBytes) > 256 {
		.paramValueBytes = make([]byte, 0, 256)
	}

	if cap(.ParamFormats) > 64 {
		.ParamFormats = make([]int16, 0, 64)
	}
	if cap(.ResultFormats) > 64 {
		.ResultFormats = make([]int16, 0, 64)
	}
}

func ( *ExtendedQueryBuilder) ( *pgtype.Map,  uint32,  int16,  any) ([]byte, error) {
	if .paramValueBytes == nil {
		.paramValueBytes = make([]byte, 0, 128)
	}

	 := len(.paramValueBytes)

	,  := .Encode(, , , .paramValueBytes)
	if  != nil {
		return nil, 
	}
	if  == nil {
		return nil, nil
	}
	.paramValueBytes = 
	return .paramValueBytes[:], nil
}

// chooseParameterFormatCode determines the correct format code for an
// argument to a prepared statement. It defaults to TextFormatCode if no
// determination can be made.
func ( *ExtendedQueryBuilder) ( *pgtype.Map,  uint32,  any) int16 {
	switch .(type) {
	case string, *string:
		return TextFormatCode
	}

	return .FormatCodeForOID()
}