package utils

import (
	"errors"
	"fmt"
	"net/http"
	"reflect"
	"strconv"
)

// MapIt maps get request into struct
func ParseQuery(req *http.Request, d interface{}) error {
	dType := reflect.TypeOf(d)

	if err := shouldBeStruct(dType); err != nil {
		return err
	}

	// Data Holder Value
	dhVal := reflect.ValueOf(d)

	// Loop over all the fields present in struct (Title, Body, JSON)
	for i := 0; i < dType.Elem().NumField(); i++ {

		// Give me ith field. Elem() is used to dereference the pointer
		field := dType.Elem().Field(i)

		// Get the value from field tag i.e in case of Title it is "title"
		key := field.Tag.Get("mapper")

		// Get the type of field
		kind := field.Type.Kind()

		// Get the value from query params with given key
		val := req.URL.Query().Get(key)

		//  Get reference of field value provided to input `d`
		result := dhVal.Elem().Field(i)

		switch kind {
		case reflect.Int:
			if val == "" {
				result.SetInt(0)
			} else {
				intVal, err := strconv.ParseInt(val, 10, 64)
				if err != nil {
					return err
				}
				result.SetInt(intVal)
			}
		case reflect.String:
			if val == "" {
				result.SetString("")
			} else {
				result.SetString(val)
			}
		}

	}
	return nil
}

func shouldBeStruct(d reflect.Type) error {
	td := d.Elem()
	if td.Kind() != reflect.Struct {
		errStr := fmt.Sprintf("Input should be %v, found %v", reflect.Struct, td.Kind())
		return errors.New(errStr)
	}
	return nil
}
