/***********************************************************************************************************
 * Name         : WelcomeEmailBatchTest
 * Purpose      : Test class for WelcomeEmailBatch along with WelcomeEmailBatchHelper
 **********************************************************************************************************/
@isTest
public with sharing class WelcomeEmailBatchTest {
    @TestSetup
    static void makeData() {
        TriggerControl.disableTrigger(DOTempFormResponseTriggerHandler.SELF);

        String territoryWithRetarget = System.Label.Retarget_Territories.split(',')[0];

        Territory__c territory = TestFactory.createTerritory(territoryWithRetarget);

        Label__c label = TestFactory.createLabel('My Label');

        TL__c tl = TestFactory.createTerritoryLabel(true);

        TLA__c tla = TestFactory.createTerritoryLabelArtist('My TLA', true, tl.Id, territory.Id, label.Id, null);

        Mailing_List__c mailingList = TestFactory.createMailingList('My ML', tla.Id);

        Form__c form = TestFactory.createForm(tla.Id, 'NewsLetter');
        form.TriggeredSendDefinitionKey__c = 'testTSDK';
        form.Parent_MID__c = '12345';
        update form;

        TestFactory.createFormML(form.Id, mailingList.Id, true, true);

        Fan__c fan = TestFactory.createFan();
        fan.Encrypted_ID__c = 'testEncryptedId';
        fan.First_Name__c = 'First';
        fan.Last_Name__c = 'Last';
        fan.Postal_Code__c = '42983420';
        update fan;

        Promotion__c promo = [SELECT Id, Name FROM Promotion__c LIMIT 1];

        Subscription__c sub = TestFactory.createSubscription(fan.id, true, mailingList.id, promo.Id);
        sub.Territory_ID__c = tla.Territory_ID__c;
        update sub;

        SubscriptionFanTriggerSendMapping__c subFan = new SubscriptionFanTriggerSendMapping__c();
        subFan.Fan_ID__c = fan.id;
        subFan.MC_MID__c = form.Parent_MID__c;
        subFan.Triggered_Send_Definition_Key__c = form.TriggeredSendDefinitionKey__c;
        subFan.Welcome_Email_Triggered__c = false;
        subFan.Welcome_Email_Delivered__c = false;
        subFan.Subscription_ID__c = sub.id;
        subFan.Form_ID__c = form.id;
        insert subFan;

        SubscriptionFanTriggerSendMapping__c extraSubFan = new SubscriptionFanTriggerSendMapping__c();
        extraSubFan.Fan_ID__c = fan.id;
        extraSubFan.MC_MID__c = form.Parent_MID__c;
        extraSubFan.Triggered_Send_Definition_Key__c = form.TriggeredSendDefinitionKey__c;
        extraSubFan.Welcome_Email_Triggered__c = false;
        extraSubFan.Welcome_Email_Delivered__c = false;
        extraSubFan.Subscription_ID__c = sub.id;
        extraSubFan.Form_ID__c = form.id;
        insert extraSubFan;

        DO_Temp_Form_Response__c objDOFR = new DO_Temp_Form_Response__c();
        objDOFR.Email__c = 'test@email.com';
        objDOFR.Welcome_Email_Delivered__c = false;
        objDOFR.triggered_send_definition_key__c = form.TriggeredSendDefinitionKey__c;
        objDOFR.formName__c = form.Form_Name__c;
        objDOFR.Is_Double_Opt_In_Form_Response__c = true;
        objDOFR.Parent_MID__c = '12345';
        objDOFR.DSP__c = 'Email';
        objDOFR.Form_ID__c = form.Id;
        insert objDOFR;

        DO_Temp_Form_Response__c extraDoTemp = new DO_Temp_Form_Response__c();
        extraDoTemp.Email__c = 'test@email.com';
        extraDoTemp.Welcome_Email_Delivered__c = false;
        extraDoTemp.triggered_send_definition_key__c = form.TriggeredSendDefinitionKey__c;
        extraDoTemp.formName__c = form.Form_Name__c;
        extraDoTemp.Is_Double_Opt_In_Form_Response__c = true;
        extraDoTemp.Parent_MID__c = '12345';
        extraDoTemp.DSP__c = 'Email';
        extraDoTemp.Form_ID__c = form.Id;
        insert extraDoTemp;

        insert new List<Config__c>{
            new Config__c(Name = 'TFR_JOB_MAX_RETRY', Value__c = '10'),
            new Config__c(Name = 'FILE_UPLOAD_JOB_MAX_RETRY', Value__c = '10'),
            new Config__c(Name = 'MC_ENDPOINT_AUTH', Value__c = 'https://token'),
            new Config__c(Name = 'MC_WELCOME_EMAIL_ENDPOINT', Value__c = 'https://welcomeEmail-{TSDK}'),
            new Config__c(Name = 'MC_WELCOME_EMAIL_CLIENT_ID', Value__c = 'testClientId'),
            new Config__c(Name = 'MC_WELCOME_EMAIL_CLIENT_SECRET', Value__c = 'testClientSecret'),
            new Config__c(Name = 'WE_JOB_KEEP_RUNNING', Value__c = 'true'),
            new Config__c(Name = 'WE_FAILURE_EMAIL_RECIPIENTS', Value__c = 'test@email.com'),
            new Config__c(Name = 'WE_FAILURE_EMAIL_SENDER', Value__c = 'Test Sender'),
            new Config__c(Name = 'WE_FAILURE_EMAIL_BODIES', Value__c = 'test body 1; test body 2'),
            new Config__c(Name = 'WE_FAILURE_EMAIL_SUBJECT_MID', Value__c = 'MID Subject'),
            new Config__c(Name = 'WE_FAILURE_EMAIL_SUBJECT_TSDK', Value__c = 'TSDK Subject'),
            new Config__c(Name = 'WE_FAILURE_EMAIL_SUBJECT_NEW_ERROR', Value__c = 'New Error Subject')
        };
    }

    /************************************************************************************
     * Method: testWelcomeEmailWithErrorAndEmailSend
     * APEX method tested : WelcomeEmailBatchHelper.createTriggeredSend
     * Description : Verifies that the record is properly updated and the email was sent
     *************************************************************************************/
    @isTest
    static void testWelcomeEmailWithErrorAndEmailSend() {
        TestFactory.WelcomeEmailBatchHelperMock mock = new TestFactory.WelcomeEmailBatchHelperMock(501);
        mock.authResponse = new MarketingCloudHelper.MarketingCloudAuthResponse();
        mock.authResponse.access_token = 'MOCKED_TOKEN';
        mock.authResponse.expires_in = 99;

        Test.startTest();
        Test.setMock(HttpCalloutMock.class, mock);
        WelcomeEmailBatch batch = new WelcomeEmailBatch(true, 1);
        Database.executeBatch(batch, 50);
        Test.stopTest();

        SubscriptionFanTriggerSendMapping__c subFanUpdated = [
            SELECT Id, Welcome_Email_Triggered__c, Welcome_Email_Delivered__c, MC_Error_Message__c, RecipientSendId__c
            FROM SubscriptionFanTriggerSendMapping__c
            LIMIT 1
        ];

        EmailMessage email = [SELECT Id, Subject, Status FROM EmailMessage];

        Assert.areEqual(false, subFanUpdated.Welcome_Email_Delivered__c);
        Assert.areEqual('Triggered send definition key not found', subFanUpdated.MC_Error_Message__c);
        Assert.areEqual(null, subFanUpdated.RecipientSendId__c);
        Assert.areEqual('TSDK Subject', email.Subject);
    }

    /************************************************************************************
     * Method: testWelcomeEmailWithErrorRetry
     * APEX method tested : WelcomeEmailBatchHelper.createTriggeredSend
     * Description : Verifies that the record is NOT updated when the error is
     * Internal server error, so that way the record will be picked up by the batch job again
     *************************************************************************************/
    @isTest
    static void testWelcomeEmailWithErrorRetry() {
        TestFactory.WelcomeEmailBatchHelperMock mock = new TestFactory.WelcomeEmailBatchHelperMock(500);
        mock.authResponse = new MarketingCloudHelper.MarketingCloudAuthResponse();
        mock.authResponse.access_token = 'MOCKED_TOKEN';
        mock.authResponse.expires_in = 99;

        Test.startTest();
        Test.setMock(HttpCalloutMock.class, mock);
        WelcomeEmailBatch batch = new WelcomeEmailBatch(true, 1);
        Database.executeBatch(batch, 50);
        Test.stopTest();

        SubscriptionFanTriggerSendMapping__c subFanUpdated = [
            SELECT Id, Welcome_Email_Triggered__c, Welcome_Email_Delivered__c, MC_Error_Message__c, RecipientSendId__c
            FROM SubscriptionFanTriggerSendMapping__c
            LIMIT 1
        ];

        Assert.areEqual(false, subFanUpdated.Welcome_Email_Delivered__c);
        Assert.areEqual(false, subFanUpdated.Welcome_Email_Triggered__c);
        Assert.areEqual(null, subFanUpdated.MC_Error_Message__c);
        Assert.areEqual(null, subFanUpdated.RecipientSendId__c);
    }

    /************************************************************************************
     * Method: testWelcomeEmailWithErrorNonExistingMID
     * APEX method tested : WelcomeEmailBatchHelper.createTriggeredSend
     * Description : Verifies that the is properly updated when recieving the
     * error Non existing MID and the email is sent
     *************************************************************************************/
    @isTest
    static void testWelcomeEmailWithErrorNonExistingMID() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new TestFactory.WelcomeEmailBatchHelperMock(500));
        WelcomeEmailBatch batch = new WelcomeEmailBatch(true, 1);
        Database.executeBatch(batch, 50);
        Test.stopTest();

        SubscriptionFanTriggerSendMapping__c subFanUpdated = [
            SELECT Id, Welcome_Email_Triggered__c, Welcome_Email_Delivered__c, MC_Error_Message__c, RecipientSendId__c
            FROM SubscriptionFanTriggerSendMapping__c
            LIMIT 1
        ];
        
        EmailMessage email = [SELECT Id, Subject, Status FROM EmailMessage];

        Assert.areEqual(false, subFanUpdated.Welcome_Email_Delivered__c);
        Assert.areEqual(true, subFanUpdated.Welcome_Email_Triggered__c);
        Assert.areEqual('Non existing MID', subFanUpdated.MC_Error_Message__c);
        Assert.areEqual(null, subFanUpdated.RecipientSendId__c);

        Assert.areEqual('MID Subject', email.Subject);
    }

    /************************************************************************************
     * Method: testWelcomeEmailSuccess
     * APEX method tested : WelcomeEmailBatchHelper.createTriggeredSend
     * Description : Verifies that the emails were sent based on the Welcome_Email_Delivered__c field.
     *************************************************************************************/
    @isTest
    static void testWelcomeEmailSuccess() {
        TestFactory.WelcomeEmailBatchHelperMock mock = new TestFactory.WelcomeEmailBatchHelperMock(202);
        mock.authResponse = new MarketingCloudHelper.MarketingCloudAuthResponse();
        mock.authResponse.access_token = 'MOCKED_TOKEN';
        mock.authResponse.expires_in = 99;

        Test.startTest();
        Test.setMock(HttpCalloutMock.class, mock);
        WelcomeEmailBatch batch = new WelcomeEmailBatch(true, 1);
        Database.executeBatch(batch, 50);
        Test.stopTest();

        List<SubscriptionFanTriggerSendMapping__c> subFanUpdatedList = [
            SELECT Id, Welcome_Email_Triggered__c, Welcome_Email_Delivered__c, MC_Error_Message__c, RecipientSendId__c
            FROM SubscriptionFanTriggerSendMapping__c
            ORDER BY CreatedDate ASC
        ];
        Assert.areEqual(false, subFanUpdatedList[0].Welcome_Email_Delivered__c);
        Assert.areEqual('InvalidOrMissingToAddress', subFanUpdatedList[0].MC_Error_Message__c);
        Assert.areEqual(null, subFanUpdatedList[0].RecipientSendId__c);

        Assert.areEqual(true, subFanUpdatedList[1].Welcome_Email_Delivered__c);
        Assert.areEqual(null, subFanUpdatedList[1].MC_Error_Message__c);
        Assert.areEqual('ecd69af4-d461-405e-95c5-65cec70ed5a5', subFanUpdatedList[1].RecipientSendId__c);
    }

    /************************************************************************************
     * Method: testDoubleOptIn
     * APEX method tested : WelcomeEmailBatchHelper.createTriggeredSend
     * Description : Verifies that the emails were sent based on the Welcome_Email_Delivered__c field.
     *************************************************************************************/
    @isTest
    static void testDoubleOptIn() {
        TestFactory.WelcomeEmailBatchHelperMock mock = new TestFactory.WelcomeEmailBatchHelperMock(202);
        mock.authResponse = new MarketingCloudHelper.MarketingCloudAuthResponse();
        mock.authResponse.access_token = 'MOCKED_TOKEN';
        mock.authResponse.expires_in = 99;

        Test.startTest();
        Test.setMock(HttpCalloutMock.class, mock);
        WelcomeEmailBatch batch = new WelcomeEmailBatch(false, 1);
        Database.executeBatch(batch, 50);
        Test.stopTest();

        List<DO_Temp_Form_Response__c> doTempsUpdated = [
            SELECT Id, Welcome_Email_Delivered__c, MC_Error_Message__c, RecipientSendId__c
            FROM DO_Temp_Form_Response__c
            ORDER BY CreatedDate ASC
        ];

        Assert.areEqual(false, doTempsUpdated[0].Welcome_Email_Delivered__c);
        Assert.areEqual('InvalidOrMissingToAddress', doTempsUpdated[0].MC_Error_Message__c);
        Assert.areEqual(null, doTempsUpdated[0].RecipientSendId__c);

        Assert.areEqual(true, doTempsUpdated[1].Welcome_Email_Delivered__c);
        Assert.areEqual(null, doTempsUpdated[1].MC_Error_Message__c);
        Assert.areEqual('ecd69af4-d461-405e-95c5-65cec70ed5a5', doTempsUpdated[1].RecipientSendId__c);
    }
}