package goscaffold

import (
	"context"
	"crypto/rsa"
	"encoding/json"
	"github.com/SermoDigital/jose/crypto"
	"github.com/SermoDigital/jose/jws"
	"github.com/julienschmidt/httprouter"
	"github.com/justinas/alice"
	"net/http"
	"sync"
	"time"
)

var (
	gPkey   *rsa.PublicKey
	rwMutex sync.RWMutex
)

const params = "params"

/* Errors to return */
type Errors []string

/*
The SSO key parameters
*/
type ssoKey struct {
	Alg   string `json:"alg"`
	Value string `json:"value"`
	Kty   string `json:"kty"`
	Use   string `json:"use"`
	N     string `json:"n"`
	E     string `json:"e"`
}

/*
OAuth structure that provides http connection to the URL that has the public
key for verifying the JWT token
*/
type OAuth struct {
}

/*
The interface functions offered to clients that act on OAuth param,
used to verify JWT tokens for the Http handler functions client
wishes to validate against (via SSOHandler).
*/
type OAuthService interface {
	SSOHandler(p string, h func(http.ResponseWriter, *http.Request)) (string, httprouter.Handle)
}

/*
CreateOAuth is a constructor that creates OAuth for OAuthService
interface. OAuthService interface offers method:-
(1) SSOHandler(): Offers the user to attach http handler for JWT
verification.
*/
func (s *HTTPScaffold) CreateOAuth(keyURL string) OAuthService {

	pk, err := getPubicKey(keyURL)
	if err != nil {
		panic("Unable to retreive Public Key")
	}
	setPkSafe(pk)
	/*
	  Routine that will fetch & update the public keys in the global
	  variable periodically
	*/
	updatePulicKeysPeriodic(keyURL)

	return &OAuth{}

}

/*
SetParamsInRequest Sets the params and its values in the request
*/
func SetParamsInRequest(r *http.Request, ps httprouter.Params) *http.Request {
	newContext := context.WithValue(r.Context(), params, ps)
	return r.WithContext(newContext)
}

/*
FetchParams fetches the param values, given the params in the request
*/
func FetchParams(r *http.Request) httprouter.Params {
	ctx := r.Context()
	return ctx.Value(params).(httprouter.Params)
}

/*
SSOHandler offers the users the flexibility of choosing which http handlers
need JWT validation.
*/
func (a *OAuth) SSOHandler(p string, h func(http.ResponseWriter, *http.Request)) (string, httprouter.Handle) {
	return p, a.VerifyOAuth(alice.New().ThenFunc(h))
}

/*
VerifyOAuth verifies the JWT token in the request using the public key configured
via CreateOAuth constructor.
*/
func (a *OAuth) VerifyOAuth(next http.Handler) httprouter.Handle {

	return func(rw http.ResponseWriter, r *http.Request, ps httprouter.Params) {

		jwt, err := jws.ParseJWTFromRequest(r)
		if err != nil {
			WriteErrorResponse(http.StatusBadRequest, err.Error(), rw)
			return
		}

		/* Validate the JWT */
		err = jwt.Validate(getPkSafe(), crypto.SigningMethodRS256)
		if err != nil {
			WriteErrorResponse(http.StatusBadRequest, err.Error(), rw)
			return
		}

		/* Set the params in the request */
		r = SetParamsInRequest(r, ps)
		next.ServeHTTP(rw, r)
	}

}

/*
WriteErrorResponse write a non 200 error response
*/
func WriteErrorResponse(statusCode int, message string, w http.ResponseWriter) {
	errors := Errors{message}
	WriteErrorResponses(statusCode, errors, w)
}

/*
WriteErrorResponses write our error responses
*/
func WriteErrorResponses(statusCode int, errors Errors, w http.ResponseWriter) {
	w.WriteHeader(statusCode)
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(errors)
}

/*
updatePulicKeysPeriodic updates the cache periodically (every day)
*/
func updatePulicKeysPeriodic(keyURL string) {

	ticker := time.NewTicker(24 * 3600 * time.Second)
	quit := make(chan struct{})
	go func() {
		for {
			select {
			case <-ticker.C:
				pk, err := getPubicKey(keyURL)
				if err == nil {
					setPkSafe(pk)
				}
			case <-quit:
				ticker.Stop()
				return
			}
		}
	}()
}

/*
getPubicKey: Loads the Public key in to memory and returns it.
*/
func getPubicKey(keyURL string) (*rsa.PublicKey, error) {

	client := &http.Client{}
	r, err := client.Get(keyURL)
	if err != nil {
		return nil, err
	}

	defer r.Body.Close()
	ssoKey := &ssoKey{}
	err = json.NewDecoder(r.Body).Decode(ssoKey)
	if err != nil {
		return nil, err
	}

	/* Retrieve the Public Key */
	publicKey, err := crypto.ParseRSAPublicKeyFromPEM([]byte(ssoKey.Value))
	if err != nil {
		return nil, err
	}
	return publicKey, nil

}

/*
setPkSafe Safely stores the Public Key (via a Write Lock)
*/
func setPkSafe(pk *rsa.PublicKey) {
	rwMutex.Lock()
	gPkey = pk
	rwMutex.Unlock()
}

/*
getPkSafe returns the stored key (via a read lock)
*/
func getPkSafe() *rsa.PublicKey {
	rwMutex.RLock()
	pk := gPkey
	rwMutex.RUnlock()
	return pk
}
