package jwt

import (
	"encoding/base64"
	"encoding/json"
	"net/http"
	"strings"

	"github.com/pkg/errors"
)

// AuthToken token json
type AuthToken struct {
	Token string `json:"token" validate:"jwt"`
}

// GetPayload decodes the token payload
func GetPayload(token string) (map[string]interface{}, error) {
	payload := map[string]interface{}{}

	data, err := parsePayload(token)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(data, &payload)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	return payload, nil
}

// GetAuthorizationHeader parses auth token from Authorization header
func GetAuthorizationHeader(r *http.Request) (AuthToken, error) {
	auth := AuthToken{}
	header := r.Header.Get(AuthenticationHeader)
	if header == "" {
		return auth, errors.New("no authorization header")
	}
	if !strings.Contains(header, "Bearer ") {
		return auth, errors.New("missing Bearer")
	}
	auth.Token = ParseJWTToken(header)
	return auth, nil
}

func ParseJWTToken(token string) string {
	return strings.ReplaceAll(token, "Bearer ", "")
}

func parsePayload(token string) ([]byte, error) {
	parts := strings.Split(token, ".")
	if len(parts) < 3 {
		return nil, errors.New("unable to parse token")
	}
	raw, err := decodeJWT(parts[1])
	if err != nil {
		return nil, err
	}

	return raw, nil
}

func decodeJWT(src string) ([]byte, error) {
	if l := len(src) % 4; l > 0 {
		src += strings.Repeat("=", 4-l)
	}

	decoded, err := base64.URLEncoding.DecodeString(src)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	return decoded, nil
}
