/***********************************************************************************************************
 * Name         : ArtistFormController
 * Purpose      : Controller of artistForm LWC
 **********************************************************************************************************/

public with sharing class ArtistFormController {
    private static final String ENCRYPTION_KEY = ConfigUtils.getConfigString(ConfigUtils.SPOTIFY_TOKEN_ENCRYPTION_KEY);

    /**
     * @description Uses a Spotify User Client Credentials to get an Access Token for later callouts
     */
    @AuraEnabled
    public static String getToken() {
        List<String> clientCredentials = ConfigUtils.getConfigMultipleStrings(
            ConfigUtils.SPOTIFY_TOKEN_API_CLIENT_CREDENTIALS
        );
        String clientId = clientCredentials[0];
        String clientSecret = clientCredentials[1];

        String body = 'grant_type=client_credentials&client_id=' + clientId + '&client_secret=' + clientSecret;

        HttpRequest request = new HttpRequest();
        request.setEndpoint(ConfigUtils.getConfigString(ConfigUtils.SPOTIFY_TOKEN_API_ENDPOINT));
        request.setMethod('POST');
        request.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        request.setHeader('grant_type', 'client_credentials');
        request.setBody(body);

        HttpResponse response = new Http().send(request);

        Map<String, Object> jsonMap = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
        String accessToken = (String) jsonMap.get('access_token');

        return encryptToken(accessToken);
    }

    /**
     * @description calls Spotify Search API to find artists by name
     * @param artistName the value typed by the user in the search bar
     * @param encryptedToken Encrypted Access Token from Spotify Token API
     */
    @AuraEnabled
    public static HttpResult searchArtist(String artistName, String encryptedToken) {
        try {
            String endpoint = ConfigUtils.getConfigString(ConfigUtils.SPOTIFY_SEARCH_API_ENDPOINT);
            endpoint = endpoint.replace('{{artist_name}}', artistName);

            HttpRequest request = new HttpRequest();
            request.setHeader('Authorization', 'Bearer ' + decryptToken(encryptedToken));
            request.setEndpoint(endpoint);
            request.setMethod('GET');

            HttpResponse response = new Http().send(request);
            return new HttpResult(response.getStatusCode(), response.getBody());
        } catch (Exception ex) {
            throw new AuraHandledException(ex.getMessage());
        }
    }

    /**
     * @description Uses a Spotify User client credentials to get an Access Token for later callouts
     * @param spotifyId the value typed by the user in the search bar
     * @param encryptedToken Encrypted Access Token from Spotify Token API
     */
    @AuraEnabled
    public static HttpResult getArtist(String spotifyId, String encryptedToken) {
        try {
            String endpoint = ConfigUtils.getConfigString(ConfigUtils.SPOTIFY_ARTIST_API_ENDPOINT);
            endpoint = endpoint.replace('{{spotify_id}}', spotifyId);

            HttpRequest request = new HttpRequest();        
            request.setHeader('Authorization', 'Bearer ' + decryptToken(encryptedToken));
            request.setEndpoint(endpoint);
            request.setMethod('GET');

            HttpResponse response = new Http().send(request);
            return new HttpResult(response.getStatusCode(), response.getBody());
        } catch (Exception ex) {
            throw new AuraHandledException(ex.getMessage());
        }
    }

    /**
     * @description Encrypt the Access Token so we don't expose it to the client side
     * @param token Access Token from Spotify Token API
     */
    public static String encryptToken(String token) {
        Blob decodedKey = EncodingUtil.base64Decode(ENCRYPTION_KEY);
        Blob encryptedBlob = Crypto.encryptWithManagedIV('AES128', decodedKey, Blob.valueOf(token));
        return EncodingUtil.base64Encode(encryptedBlob);
    }

    /**
     * @description Dencrypt the Access Token so it can be used in the Spotify APIs
     * @param token Encrypted Access Token
     */
    public static String decryptToken(String encryptedToken) {
        Blob decodedKey = EncodingUtil.base64Decode(ENCRYPTION_KEY);
        Blob encryptedBlob = EncodingUtil.base64Decode(encryptedToken);
        Blob decryptedBlob = Crypto.decryptWithManagedIV('AES128', decodedKey, encryptedBlob);
        return decryptedBlob.toString();
    }

    public class HttpResult {
        @AuraEnabled
        public Integer statusCode;

        @AuraEnabled
        public String data;

        public HttpResult(Integer statusCode, String data) {
            this.statusCode = statusCode;
            this.data = data;
        }
    }
}