/***********************************************************************************************************
 * Name         : FanMCAllContactsVerificationBatchTest
 * Purpose      : Test class for FanMCAllContactsVerificationBatch
 **********************************************************************************************************/
@isTest
public with sharing class FanMCAllContactsVerificationBatchTest {
    @TestSetup
    static void makeData() {
        insert new List<Config__c>{
            new Config__c(Name = 'MC_ENDPOINT_AUTH', Value__c = 'https://token'),
            new Config__c(Name = 'MC_ALL_CONTACTS_CLIENT_ID', Value__c = '1234'),
            new Config__c(Name = 'MC_ALL_CONTACTS_CLIENT_SECRET', Value__c = '5678'),
            new Config__c(Name = 'TFR_JOB_MAX_RETRY', Value__c = '3'),
            new Config__c(Name = 'FILE_UPLOAD_JOB_MAX_RETRY', Value__c = '3'),
            new Config__c(Name = 'MC_ENDPOINT_CONTACTS_DELETE_STATUS', Value__c = 'https://verification='),
            new Config__c(Name = 'MC_VERIFICATION_BATCH_CRON_EXP', Value__c = '0 0 1 * * ?'),
            new Config__c(Name = 'MC_VERIFICATION_BATCH_RECIPIENTS', Value__c = 'test@email.com'),
            new Config__c(Name = 'MC_VERIFICATION_BATCH_SENDER', Value__c = 'Verification batch'),
            new Config__c(Name = 'MC_VERIFICATION_BATCH_SUBJECT', Value__c = 'Verification subject'),
            new Config__c(Name = 'MC_VERIFICATION_BATCH_EMAIL_BODIES', Value__c = 'message1;message2')
        };

        Fan_MC_Cleanup__c fanMc = new Fan_MC_Cleanup__c();
        fanMc.Name = 'test1';
        fanMc.Delete_Request_Triggered__c = true;
        fanMc.Fan_ID__c = 'fanIdTest';
        fanMc.CreatedDate = System.today() - 7;
        fanMc.LastModifiedDate = System.today() - 7;
        fanMc.Is_Deleted_From_MC_All_Subscribers__c = false;
        fanMc.Operation_ID__c = '12345';
        fanMc.Status__c = null;
        fanMc.MC_Error_Message__c = null;
        fanMc.TimesChecked__c = 0;
        insert fanMc;
    }

    /************************************************************************************
     * Method: verificationCalloutDeletedFromMC
     * APEX method tested : FanMCAllContactsVerificationBatchHelper.performVerificationCallout
     * Description : verifies that the Fan_MC_Cleanup__c was deleted from MC
     *************************************************************************************/
    @isTest
    static void verificationCalloutDeletedFromMC() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new FanMCAllContactsVerificationMock(200, false, false));
        FanMCAllContactsVerificationBatch batch = new FanMCAllContactsVerificationBatch();
        Database.executeBatch(batch);
        Test.stopTest();

        List<Fan_MC_Cleanup__c> listFanMcUpdated = [
            SELECT Id, Is_Deleted_From_MC_All_Subscribers__c, MC_Error_Message__c, Status__c
            FROM Fan_MC_Cleanup__c
            LIMIT 1
        ];
        System.assertEquals(0, listFanMcUpdated.size());
    }

    /************************************************************************************
     * Method: verificationCalloutStillProcessing
     * APEX method tested : FanMCAllContactsVerificationBatchHelper.performVerificationCallout
     * Description : verifies that the Fan_MC_Cleanup__c was NOT deleted from MC
     *************************************************************************************/
    @isTest
    static void verificationCalloutStillProcessing() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new FanMCAllContactsVerificationMock(200, true, false));
        FanMCAllContactsVerificationBatch batch = new FanMCAllContactsVerificationBatch();
        Database.executeBatch(batch);
        Test.stopTest();

        Fan_MC_Cleanup__c fanMcUpdated = [
            SELECT Id, Is_Deleted_From_MC_All_Subscribers__c, MC_Error_Message__c, Status__c
            FROM Fan_MC_Cleanup__c
            LIMIT 1
        ];
        System.assertEquals(false, fanMcUpdated.Is_Deleted_From_MC_All_Subscribers__c);
        System.assertEquals('Processing', fanMcUpdated.Status__c);
        System.assertEquals(null, fanMcUpdated.MC_Error_Message__c);
    }

    /************************************************************************************
     * Method: verificationCalloutOpIdNotFound
     * APEX method tested : FanMCAllContactsVerificationBatchHelper.performVerificationCallout
     * Description : verifies that the operation Id was not found in MC
     *************************************************************************************/
    @isTest
    static void verificationCalloutOpIdNotFound() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new FanMCAllContactsVerificationMock(200, true, true));
        FanMCAllContactsVerificationBatch batch = new FanMCAllContactsVerificationBatch();
        Database.executeBatch(batch);
        Test.stopTest();

        Fan_MC_Cleanup__c fanMcUpdated = [
            SELECT Id, Is_Deleted_From_MC_All_Subscribers__c, MC_Error_Message__c, Status__c
            FROM Fan_MC_Cleanup__c
            LIMIT 1
        ];
        System.assertEquals(false, fanMcUpdated.Is_Deleted_From_MC_All_Subscribers__c);
        System.assertEquals('OperationID not found', fanMcUpdated.Status__c);
        System.assertEquals('The referenced OperationID was not found.', fanMcUpdated.MC_Error_Message__c);
    }

    /************************************************************************************
     * Method: verificationCalloutReprocessNextDay
     * APEX method tested : FanMCAllContactsVerificationBatchHelper.performVerificationCallout
     * Description : verifies that the Fan_MC_Cleanup__c will be reprocessed on the next day,
     * in case the previous day it was already verified and NOT deleted from MC
     *************************************************************************************/
    @isTest
    static void verificationCalloutReprocessNextDay() {
        Fan_MC_Cleanup__c fanMcChecked = new Fan_MC_Cleanup__c();
        fanMcChecked.Name = 'test2';
        fanMcChecked.Delete_Request_Triggered__c = true;
        fanMcChecked.Fan_ID__c = 'fanIdTest';
        fanMcChecked.CreatedDate = System.today() - 8;
        fanMcChecked.LastModifiedDate = System.today() - 1;
        fanMcChecked.Is_Deleted_From_MC_All_Subscribers__c = false;
        fanMcChecked.Operation_ID__c = '6789';
        fanMcChecked.Status__c = 'Processing';
        fanMcChecked.MC_Error_Message__c = null;
        fanMcChecked.TimesChecked__c = 1;
        insert fanMcChecked;

        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new FanMCAllContactsVerificationMock(200, false, false));
        FanMCAllContactsVerificationBatch batch = new FanMCAllContactsVerificationBatch();
        Database.executeBatch(batch);
        Test.stopTest();

        List<Fan_MC_Cleanup__c> listFanMcUpated = [
            SELECT Id, Is_Deleted_From_MC_All_Subscribers__c, MC_Error_Message__c, Status__c, Operation_ID__c
            FROM Fan_MC_Cleanup__c
            WHERE Operation_ID__c = '6789'
            LIMIT 1
        ];

        System.assertEquals(0, listFanMcUpated.size());
    }

    /************************************************************************************
     * Method: verificationCalloutBadRequestTest
     * APEX method tested : FanMCAllContactsVerificationBatchHelper.performVerificationCallout
     * Description : verifies that the Fan_MC_Cleanup__c has the MC_Error_Message__c
     * field updated with the error description
     *************************************************************************************/
    @isTest
    static void verificationCalloutBadRequestTest() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new FanMCAllContactsVerificationMock(400, true, false));
        FanMCAllContactsVerificationBatch batch = new FanMCAllContactsVerificationBatch();
        Database.executeBatch(batch);
        Test.stopTest();

        Fan_MC_Cleanup__c fanMcUpdated = [
            SELECT Id, Is_Deleted_From_MC_All_Subscribers__c, MC_Error_Message__c, Status__c
            FROM Fan_MC_Cleanup__c
            LIMIT 1
        ];
        System.assertEquals(false, fanMcUpdated.Is_Deleted_From_MC_All_Subscribers__c);
        System.assertEquals('Bad request', fanMcUpdated.MC_Error_Message__c);
    }

    /************************************************************************************
     * Method: testSchedule
     * APEX method tested : FanMCAllContactsVerificationBatch.schedule
     * Description : Verifies that the job is being scheduled correctly
     *************************************************************************************/
    @isTest
    static void testSchedule() {
        String jobName = 'FanMCAllContactsVerificationBatch';

        List<CronJobDetail> jobs = [
            SELECT Id
            FROM CronJobDetail
            WHERE Name = :jobName
        ];

        Test.setMock(HttpCalloutMock.class, new FanMCAllContactsVerificationMock(200, false, false));

        Test.startTest();
        FanMCAllContactsVerificationBatch.schedule();
        Test.stopTest();

        jobs = [
            SELECT Id
            FROM CronJobDetail
            WHERE Name = :jobName
        ];

        Assert.areEqual(1, jobs.size());
    }

    public class FanMCAllContactsVerificationMock implements HttpCalloutMock {
        Integer statusCode;
        Boolean hasErrors;
        Boolean opIdNotFound;
        public FanMCAllContactsVerificationMock(Integer statusCode, Boolean hasErrors, Boolean opIdNotFound) {
            this.statusCode = statusCode;
            this.hasErrors = hasErrors;
            this.opIdNotFound = opIdNotFound;
        }
        public HTTPResponse respond(HTTPRequest req) {
            HTTPResponse response = new HTTPResponse();
            response.setStatusCode(statusCode);
            String responseBody = '';
            if (req.getEndpoint().contains('token')) {
                responseBody = '{"access_token":"123817","expires_in":31}';
            } else if (statusCode == 200 && !hasErrors) {
                responseBody =
                    '{"backgroundOperationsSummary": [{"backgroundOperationStatusID": "Completed"}]' +
                    ',"operation": {"status": "Completed"}, "hasErrors":false, "resultMessages": []}';
            } else if (statusCode == 200 && hasErrors && opIdNotFound) {
                responseBody = '{"hasErrors":true, "resultMessages": [{"message":"The referenced OperationID was not found."}]}';
            } else if (statusCode == 200 && hasErrors && !opIdNotFound) {
                responseBody = '{"hasErrors":true, "resultMessages": []}';
            } else {
                responseBody = '{"message":"Bad request"}';
            }
            response.setBody(responseBody);
            response.setStatus('OK');
            return response;
        }
    }
}
