// https://developer.fastly.com/solutions/examples/normalize-requests

package main

import (
	"context"
	"fmt"
	"io"
  "net/url"
  "strings"

	"github.com/fastly/compute-sdk-go/fsthttp"
)

// BackendName is the name of our service backend.
const BackendName = "origin_0"

func main() {
	fsthttp.ServeFunc(func(ctx context.Context, w fsthttp.ResponseWriter, r *fsthttp.Request) {
		// This requires your service to be configured with a backend
		// named "origin_0" and pointing to "https://http-me.glitch.me".
    
    // Filter query strings to only include query
    // parameters that are valid for your site
    qs := r.URL.Query()
    // Query strings parameters to keep. 
    keep := []string{"query", "page", "foo"}
    qs = FilterExcept(qs, keep)

    // Lowercase specific query string values.
    qs.Set("query", strings.ToLower(qs.Get("query")))

    // Encode() encodes the query string parameters into URL encoded form.
    // And sorts them in alphabetical order.
    r.URL.RawQuery =  qs.Encode()

    // Remove headers that you want to avoid using to vary responses.
    r.Header.Del("user-agent")
    r.Header.Del("cookie")

    // Normalize headers that you may vary on.
    // Normalize the Accept-Language header.
    LangAccept := []string{"en", "de", "fr", "nl"}
    LangDefault := "de"
    LangNorm := NormAccept(r.Header.Get("accept-language"), LangAccept, LangDefault)
    r.Header.Set("accept-language", LangNorm)

		resp, err := r.Send(ctx, BackendName)
		if err != nil {
			w.WriteHeader(fsthttp.StatusBadGateway)
			fmt.Fprintln(w, err.Error())
			return
		}

		w.Header().Reset(resp.Header)
		w.WriteHeader(resp.StatusCode)
		io.Copy(w, resp.Body)
	})
}

// filterExcept() function takes in all query string parameters and a list
// of parameters to keep and returns only a map of parameters to keep.
func FilterExcept(q url.Values, f []string) url.Values {
	new := make(url.Values)
	for _, val := range f {
		for key, element := range q {
			if key == val {
				new[key] = element
			}
		}
	}
	return new
}

// headerAccept() function checks the input against a list of accepted values
// and returns a value in the list or the default value if no match is found.
// Disclaimer: This function is only a simple demonstration on how the accept
// header can be normalized. For production usage please use a dedicated package.
func NormAccept(input string, accept []string, def string) string {
	f := 0
	var result string
	for _, val := range accept {
		if strings.Contains(input, val) {
			f = 1
			result = val
			break
		}
	}
	if f == 1 {
		return result
	} else {
		return def
	}
}