package runtime

import (
	
	
	
	
	
	
	
	
	

	
)

func ( interface{},  []string) ([]string, error) {
	var  []string

	switch t := .(type) {
	case []interface{}:
		// For the array, we will use numerical subscripts of the form [x],
		// in the same order as the array.
		for ,  := range  {
			 := append(, strconv.Itoa())
			,  := (, )
			if  != nil {
				return nil, fmt.Errorf("error traversing array: %w", )
			}
			 = append(, ...)
		}
	case map[string]interface{}:
		// For a map, each key (field name) becomes a member of the path, and
		// we recurse. First, sort the keys.
		 := make([]string, len())
		 := 0
		for  := range  {
			[] = 
			++
		}
		sort.Strings()

		// Now, for each key, we recursively marshal it.
		for ,  := range  {
			 := append(, )
			,  := ([], )
			if  != nil {
				return nil, fmt.Errorf("error traversing map: %w", )
			}
			 = append(, ...)
		}
	default:
		// Now, for a concrete value, we will turn the path elements
		// into a deepObject style set of subscripts. [a, b, c] turns into
		// [a][b][c]
		 := "[" + strings.Join(, "][") + "]"
		 = []string{
			 + fmt.Sprintf("=%v", ),
		}
	}
	return , nil
}

func ( interface{},  string) (string, error) {
	// We're going to marshal to JSON and unmarshal into an interface{},
	// which will use the json pkg to deal with all the field annotations. We
	// can then walk the generic object structure to produce a deepObject. This
	// isn't efficient and it would be more efficient to reflect on our own,
	// but it's complicated, error-prone code.
	,  := json.Marshal()
	if  != nil {
		return "", fmt.Errorf("failed to marshal input to JSON: %w", )
	}
	var  interface{}
	 = json.Unmarshal(, &)
	if  != nil {
		return "", fmt.Errorf("failed to unmarshal JSON: %w", )
	}
	,  := marshalDeepObject(, nil)
	if  != nil {
		return "", fmt.Errorf("error traversing JSON structure: %w", )
	}

	// Prefix the param name to each subscripted field.
	for  := range  {
		[] =  + []
	}
	return strings.Join(, "&"), nil
}

type fieldOrValue struct {
	fields map[string]fieldOrValue
	value  string
}

func ( *fieldOrValue) ( []string,  string) {
	 := [0]
	if len() == 1 {
		.fields[] = fieldOrValue{value: }
		return
	}

	,  := .fields[]
	if ! {
		 = fieldOrValue{
			fields: make(map[string]fieldOrValue),
		}
		.fields[] = 
	}
	.([1:], )
}

func ( [][]string,  []string) fieldOrValue {

	 := fieldOrValue{
		fields: make(map[string]fieldOrValue),
	}
	for  := range  {
		 := []
		 := []
		.appendPathValue(, )
	}
	return 
}

func ( interface{},  string,  url.Values) error {
	// Params are all the query args, so we need those that look like
	// "paramName["...
	var  []string
	var  []string
	 :=  + "["
	for ,  := range  {
		if strings.HasPrefix(, ) {
			// trim the parameter name from the full name.
			 = [len():]
			 = append(, )
			if len() != 1 {
				return fmt.Errorf("%s has multiple values", )
			}
			 = append(, [0])
		}
	}

	// Now, for each field, reconstruct its subscript path and value
	 := make([][]string, len())
	for ,  := range  {
		 = strings.TrimLeft(, "[")
		 = strings.TrimRight(, "]")
		[] = strings.Split(, "][")
	}

	 := makeFieldOrValue(, )
	 := assignPathValues(, )
	if  != nil {
		return fmt.Errorf("error assigning value to destination: %w", )
	}

	return nil
}

// This returns a field name, either using the variable name, or the json
// annotation if that exists.
func ( reflect.StructField) string {
	 := .Name
	,  := .Tag.Lookup("json")
	if  {
		// If we have a json field, and the first part of it before the
		// first comma is non-empty, that's our field name.
		 := strings.Split(, ",")
		if [0] != "" {
			 = [0]
		}
	}
	return 
}

// Create a map of field names that we'll see in the deepObject to reflect
// field indices on the given type.
func ( interface{}) (map[string]int, error) {
	 := reflect.TypeOf()
	if .Kind() != reflect.Struct {
		return nil, errors.New("expected a struct as input")
	}

	 := .NumField()
	 := make(map[string]int)
	for  := 0;  < ; ++ {
		 := .Field()
		 := getFieldName()
		[] = 
	}
	return , nil
}

func ( interface{},  fieldOrValue) error {
	//t := reflect.TypeOf(dst)
	 := reflect.ValueOf()

	 := reflect.Indirect()
	 := .Type()

	switch .Kind() {
	case reflect.Map:
		 := reflect.MakeMap(.Type())
		for ,  := range .fields {
			 := reflect.ValueOf()
			 := reflect.New(.Type().Elem())
			 := (.Interface(), )
			if  != nil {
				return fmt.Errorf("error binding map: %w", )
			}
			.SetMapIndex(, .Elem())
		}
		.Set()
		return nil
	case reflect.Slice:
		 := len(.fields)
		 := reflect.MakeSlice(, , )
		 := assignSlice(, )
		if  != nil {
			return fmt.Errorf("error assigning slice: %w", )
		}
		.Set()
		return nil
	case reflect.Struct:
		// Some special types we care about are structs. Handle them
		// here. They may be redefined, so we need to do some hoop
		// jumping. If the types are aliased, we need to type convert
		// the pointer, then set the value of the dereference pointer.

		// We check to see if the object implements the Binder interface first.
		if ,  := .Interface().(Binder);  {
			return .Bind(.value)
		}
		// Then check the legacy types
		if .ConvertibleTo(reflect.TypeOf(types.Date{})) {
			var  types.Date
			var  error
			.Time,  = time.Parse(types.DateFormat, .value)
			if  != nil {
				return fmt.Errorf("invalid date format: %w", )
			}
			 := 
			if  != reflect.TypeOf(types.Date{}) {
				// Types are aliased, convert the pointers.
				 := .Addr()
				 := .Convert(reflect.TypeOf(&types.Date{}))
				 = reflect.Indirect()
			}
			.Set(reflect.ValueOf())
		}
		if .ConvertibleTo(reflect.TypeOf(time.Time{})) {
			var  time.Time
			var  error
			,  = time.Parse(time.RFC3339Nano, .value)
			if  != nil {
				// Fall back to parsing it as a date.
				// TODO: why is this marked as an ineffassign?
				,  = time.Parse(types.DateFormat, .value) //nolint:ineffassign,staticcheck
				if  != nil {
					return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", .value, )
				}
				return fmt.Errorf("invalid date format: %w", )
			}
			 := 
			if  != reflect.TypeOf(time.Time{}) {
				// Types are aliased, convert the pointers.
				 := .Addr()
				 := .Convert(reflect.TypeOf(&time.Time{}))
				 = reflect.Indirect()
			}
			.Set(reflect.ValueOf())
		}
		,  := fieldIndicesByJSONTag(.Interface())
		if  != nil {
			return fmt.Errorf("failed enumerating fields: %w", )
		}
		for ,  := range sortedFieldOrValueKeys(.fields) {
			 := .fields[]
			,  := []
			if ! {
				return fmt.Errorf("field [%s] is not present in destination object", )
			}
			 := .Field()
			 = (.Addr().Interface(), )
			if  != nil {
				return fmt.Errorf("error assigning field [%s]: %w", , )
			}
		}
		return nil
	case reflect.Ptr:
		// If we have a pointer after redirecting, it means we're dealing with
		// an optional field, such as *string, which was passed in as &foo. We
		// will allocate it if necessary, and call ourselves with a different
		// interface.
		 := reflect.New(.Elem())
		 := .Interface()
		 := (, )
		.Set()
		return 
	case reflect.Bool:
		,  := strconv.ParseBool(.value)
		if  != nil {
			return fmt.Errorf("expected a valid bool, got %s", .value)
		}
		.SetBool()
		return nil
	case reflect.Float32:
		,  := strconv.ParseFloat(.value, 32)
		if  != nil {
			return fmt.Errorf("expected a valid float, got %s", .value)
		}
		.SetFloat()
		return nil
	case reflect.Float64:
		,  := strconv.ParseFloat(.value, 64)
		if  != nil {
			return fmt.Errorf("expected a valid float, got %s", .value)
		}
		.SetFloat()
		return nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		,  := strconv.ParseInt(.value, 10, 64)
		if  != nil {
			return fmt.Errorf("expected a valid int, got %s", .value)
		}
		.SetInt()
		return nil
	case reflect.String:
		.SetString(.value)
		return nil
	default:
		return errors.New("unhandled type: " + .String())
	}
}

func ( reflect.Value,  fieldOrValue) error {
	// Gather up the values
	 := len(.fields)
	 := make([]string, )
	// We expect to have consecutive array indices in the map
	for  := 0;  < ; ++ {
		 := strconv.Itoa()
		,  := .fields[]
		if ! {
			return errors.New("array deepObjects must have consecutive indices")
		}
		[] = .value
	}

	// This could be cleaner, but we can call into assignPathValues to
	// avoid recreating this logic.
	for  := 0;  < ; ++ {
		 := .Index().Addr()
		 := assignPathValues(.Interface(), fieldOrValue{value: []})
		if  != nil {
			return fmt.Errorf("error binding array: %w", )
		}
	}

	return nil
}

func ( map[string]fieldOrValue) []string {
	 := make([]string, 0, len())
	for  := range  {
		 = append(, )
	}
	sort.Strings()
	return 
}