/***********************************************************************************************************
 * Name         : RefreshNodeJsAuth0Token
 * Purpose      : Schedulable class to refresh the NodeJs auth0 Token
 **********************************************************************************************************/
public with sharing class RefreshNodeJsAuth0Token implements Schedulable {
    public void execute(SchedulableContext sc) {
        refreshTokenFuture();
    }

    /**
     * @description Performs an API call to get an auth0 Token and updates
     *  the Auth0__c record. It's a future method to avoid 
     *  "Callout from scheduled Apex not supported" error.
     */
    @future(callout=true)
    public static void refreshTokenFuture() {
        Auth0__c nodeJsAuth0 = [
            SELECT
                Auth_Endpoint__c,
                Token__c,
                ClientId__c,
                ClientSecret__c,
                Audience__c,
                GrantType__c,
                Token_Expiration_Time__c,
                Token_Last_Refresh_Date__c
            FROM Auth0__c
            WHERE Name = :UtilConstants.AUTH0_NODEJS
            LIMIT 1
        ];

        HttpRequest request = new HttpRequest();
        request.setEndpoint(nodeJsAuth0.Auth_Endpoint__c);
        request.setMethod('POST');
        request.setHeader('Content-Type', 'application/json');
        request.setTimeout(120000);
        request.setBody(
            '{"client_id":"' +
                nodeJsAuth0.ClientId__c +
                '", "client_secret": "' +
                nodeJsAuth0.ClientSecret__c +
                '", "audience": "' +
                nodeJsAuth0.Audience__c +
                '", "grant_type": "' +
                nodeJsAuth0.GrantType__c +
                '"}'
        );

        HttpResponse response = new Http().send(request);
        Auth0TokenWrapper tokenWrapper = (Auth0TokenWrapper) JSON.deserialize(
            response.getBody(),
            Auth0TokenWrapper.class
        );

        nodeJsAuth0.Token__c = tokenWrapper.access_token;
        nodeJsAuth0.Token_Last_Refresh_Date__c = System.now();
        nodeJsAuth0.Token_Expiration_Time__c = System.now().addSeconds(tokenWrapper.expires_in);
        update nodeJsAuth0;
    }

    public static void schedule() {
        BatchJobUtils.scheduleJob(
            new RefreshNodeJsAuth0Token(),
            ConfigUtils.getConfigString(ConfigUtils.NODEJS_TOKEN_REFRESH_CRON_EXP)
        );
    }

    @TestVisible
    private class Auth0TokenWrapper {
        public String access_token;
        public Integer expires_in;
        public String token_type;

        @TestVisible
        private Auth0TokenWrapper(String access_token, Integer expires_in, String token_type) {
            this.access_token = access_token;
            this.expires_in = expires_in;
            this.token_type = token_type;
        }
    }
}
