package api

import (
	"context"
	"net/http"

	"reichard.io/imagini/graph/model"
)

type Middleware func(http.Handler) http.HandlerFunc

func multipleMiddleware(h http.HandlerFunc, m ...Middleware) http.HandlerFunc {
	if len(m) < 1 {
		return h
	}
	wrapped := h
	for i := len(m) - 1; i >= 0; i-- {
		wrapped = m[i](wrapped)
	}
	return wrapped
}

/**
 * This is used for the graphQL endpoints that may require access to the
 * Request and ResponseWriter variables. These are used to get / set cookies.
 **/
func (api *API) queryMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		// TODO: REMOVE (SOME OF) THIS!! Only for developement due to CORS
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Expose-Headers", "*")
		w.Header().Set("Access-Control-Allow-Headers", "*")
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")

		authContext := &model.AuthContext{
			AuthResponse: &w,
			AuthRequest:  r,
		}

		// Add context
		ctx := context.WithValue(r.Context(), "auth", authContext)
		r = r.WithContext(ctx)

		next.ServeHTTP(w, r)
	})
}

/**
 * This is used for non graphQL endpoints that require authentication.
 **/
func (api *API) authMiddleware(next http.Handler) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		// TODO: REMOVE (SOME OF) THIS!! Only for developement due to CORS
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		//w.Header().Set("Access-Control-Expose-Headers", "*")
		w.Header().Set("Access-Control-Allow-Headers", "x-imagini-accesstoken,x-imagini-refreshtoken")
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")

		// CORS Preflight
		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusOK)
			return
		}

		// Validate Tokens
		accessToken, err := api.validateTokens(&w, r)
		if err != nil {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		// Create Context
		authContext := &model.AuthContext{
			AccessToken: &accessToken,
		}
		ctx := context.WithValue(r.Context(), "auth", authContext)
		r = r.WithContext(ctx)

		next.ServeHTTP(w, r)
	})
}
