<?php

namespace Twilio\Jwt;


use Twilio\Jwt\Grants\Grant;

class AccessToken {
    private $signingKeySid;
    private $accountSid;
    private $secret;
    private $ttl;
    private $identity;
    private $nbf;
    /** @var Grant[] $grants */
    private $grants;
    /** @var string[] $customClaims */
    private $customClaims;

    public function __construct($accountSid, $signingKeySid, $secret, $ttl = 3600, $identity = null) {
        $this->signingKeySid = $signingKeySid;
        $this->accountSid = $accountSid;
        $this->secret = $secret;
        $this->ttl = $ttl;

        if (!is_null($identity)) {
            $this->identity = $identity;
        }

        $this->grants = array();
        $this->customClaims = array();
    }

    /**
     * Set the identity of this access token
     *
     * @param string $identity identity of the grant
     *
     * @return $this updated access token
     */
    public function setIdentity($identity) {
        $this->identity = $identity;
        return $this;
    }

    /**
     * Returns the identity of the grant
     *
     * @return string the identity
     */
    public function getIdentity() {
        return $this->identity;
    }

    /**
     * Set the nbf of this access token
     *
     * @param integer $nbf nbf in epoch seconds of the grant
     *
     * @return $this updated access token
     */
    public function setNbf($nbf) {
        $this->nbf = $nbf;
        return $this;
    }

    /**
     * Returns the nbf of the grant
     *
     * @return integer the nbf in epoch seconds
     */
    public function getNbf() {
        return $this->nbf;
    }

    /**
     * Add a grant to the access token
     *
     * @param Grant $grant to be added
     *
     * @return $this the updated access token
     */
    public function addGrant(Grant $grant) {
        $this->grants[] = $grant;
        return $this;
    }

    /**
     * Allows to set custom claims, which then will be encoded into JWT payload.
     *
     * @param string $name
     * @param string $value
     */
    public function addClaim($name, $value) {
        $this->customClaims[$name] = $value;
    }

    public function toJWT($algorithm = 'HS256') {
        $header = array(
            'cty' => 'twilio-fpa;v=1',
            'typ' => 'JWT'
        );

        $now = time();

        $grants = array();
        if ($this->identity) {
            $grants['identity'] = $this->identity;
        }

        foreach ($this->grants as $grant) {
            $payload = $grant->getPayload();
            if (empty($payload)) {
                $payload = json_decode('{}');
            }

            $grants[$grant->getGrantKey()] = $payload;
        }

        if (empty($grants)) {
            $grants = json_decode('{}');
        }

        $payload = array_merge($this->customClaims, array(
            'jti' => $this->signingKeySid . '-' . $now,
            'iss' => $this->signingKeySid,
            'sub' => $this->accountSid,
            'exp' => $now + $this->ttl,
            'grants' => $grants
        ));

        if (!is_null($this->nbf)) {
            $payload['nbf'] = $this->nbf;
        }

        return JWT::encode($payload, $this->secret, $algorithm, $header);
    }

    public function __toString() {
        return $this->toJWT();
    }
}
