// Copyright (C) 2018 Marius Schellenberger

package jwt

import (
	"encoding/json"
	"strings"
)

// Token represents a JWT token
type Token struct {
	raw          string
	data         string
	signature    string
	rawSignature []byte
	Header       Claims
	Claims       Claims
}

// String returns the tokens encoded string
func (t *Token) String() string {
	return t.raw
}

// Sig returns the tokens URLEncoded signature
func (t *Token) Sig() string {
	return t.signature
}

// RawSig returns the tokens raw signature
func (t *Token) RawSig() []byte {
	return t.rawSignature
}

// Data returns the first two URLEncoded token fields
func (t *Token) Data() string {
	return t.data
}

// NewToken returns a new *Token using the provided hash algorithm and claims
// If claims is nil, an empty map is used
// If hash is nil, HS256 is used
func NewToken(claims Claims, hash Hash) *Token {
	if claims == nil {
		claims = make(Claims)
	}
	if hash == nil {
		hash = NewHS256()
	}
	return &Token{
		Header: Claims{
			AlgClaim: hash.Alg(),
			TypClaim: Typ,
		},
		Claims: claims,
	}
}

// DecodeToken decodes a raw string token into a *Token object
func DecodeToken(token string) (t *Token, err error) {
	if token == "" {
		return nil, ErrEmptyToken
	}
	parts := strings.Split(token, TokenSeparator)
	if len(parts) < 3 {
		return nil, ErrMissingTokenParts
	}
	if len(parts) > 3 {
		return nil, ErrNoJWT
	}
	for _, v := range parts {
		if v == "" {
			return nil, ErrNoJWT
		}
	}
	t = new(Token)
	header, err := enc.DecodeString(parts[0])
	if err != nil {
		return
	}
	err = json.Unmarshal(header, &t.Header)
	if err != nil {
		return
	}
	claims, err := enc.DecodeString(parts[1])
	if err != nil {
		return
	}
	err = json.Unmarshal(claims, &t.Claims)
	if err != nil {
		return
	}
	t.rawSignature, err = enc.DecodeString(parts[2])
	t.signature = parts[2]
	t.data = parts[0] + TokenSeparator + parts[1]
	t.raw = token
	return
}
