/***********************************************************************************************************
 * Name         : SubUploadBatchUtilsTest
 * Purpose      : Test class for SubUploadBatchUtils
 **********************************************************************************************************/

@isTest
private class SubUploadBatchUtilsTest {
    @TestSetup
    static void makeData() {
        Artist__c artist = TestFactory.createArtist();
        Label__c label = TestFactory.createLabel();
        Territory__c territory = TestFactory.createTerritory();
        TL__c tl = TestFactory.createTerritoryLabel(territory.Id, true);
        Tla__c tla = TestFactory.createTerritoryLabelArtist('TLA', true, tl.Id, territory.Id, label.Id, null);
        Mailing_List__c ml = TestFactory.createMailingList('ML', tla.Id);

        Sub_Upload_Util__c subUpload = new Sub_Upload_Util__c();
        subUpload.Name = 'Test';
        subUpload.Mailing_List__c = ml.Id;
        subUpload.Territory__c = territory.Id;
        subUpload.Artist__c = artist.Id;
        subUpload.Label__c = label.Id;
        subUpload.File_Source_Description__c = 'Test';
        subUpload.File_Uploaded__c = true;
        subUpload.DSP__c = 'Email';
        insert subUpload;
    }

    /************************************************************************************
     * Method: getFormCreate
     * APEX method tested : SubUploadBatchUtils.getForm
     * Description : Verifies that a Form is created if it does not previously exist
     *************************************************************************************/
    @IsTest
    static void getFormCreate() {
        Sub_Upload_Util__c subUpload = [
            SELECT Mailing_List__r.TLA_ID__c, File_Source_Description__c, AcquisitionChannel__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];

        Test.startTest();
        Id formId = SubUploadBatchUtils.getForm(subUpload);
        Test.stopTest();

        System.assertNotEquals(null, formId);
        Form__c form = [
            SELECT Id, TLA_ID__c, Form_Name__c, Description__c, Name__c, Form_Tool_Name__c
            FROM Form__c
            WHERE ID = :formId
        ];

        Assert.areEqual(subUpload.Mailing_List__r.TLA_ID__c, form.TLA_ID__c);
        Assert.areEqual(subUpload.File_Source_Description__c, form.Form_Name__c);
        Assert.areEqual(subUpload.File_Source_Description__c, form.Description__c);
        Assert.areEqual(subUpload.File_Source_Description__c, form.Name__c);
        Assert.areEqual(UtilConstants.FILE_UPLOAD, form.Form_Tool_Name__c);
    }

    /************************************************************************************
     * Method: getFormExisting
     * APEX method tested : SubUploadBatchUtils.getForm
     * Description : Verifies that the existing Form is returned
     *************************************************************************************/
    @IsTest
    static void getFormExisting() {
        Sub_Upload_Util__c subUpload = [
            SELECT Mailing_List__r.TLA_ID__c, File_Source_Description__c, AcquisitionChannel__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];

        Test.startTest();
        Id firstFormId = SubUploadBatchUtils.getForm(subUpload);
        Id secondFormId = SubUploadBatchUtils.getForm(subUpload);
        Test.stopTest();

        Assert.areEqual(firstFormId, secondFormId);
    }

    /************************************************************************************
     * Method: populatePromo
     * APEX method tested : SubUploadBatchUtils.populatePromo
     * Description : Verifies that the subUpload Promo field is updated
     *************************************************************************************/
    @IsTest
    static void populatePromo() {
        Sub_Upload_Util__c subUpload = [
            SELECT Mailing_List__r.TLA_ID__c, File_Source_Description__c, Promo_ID__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];

        Assert.areEqual(null, subUpload.Promo_ID__c);
        Form__c form = TestFactory.getForm(subUpload.Mailing_List__r.TLA_ID__c);
        form.Form_Name__c = subUpload.File_Source_Description__c;
        insert form;
        Promotion__c promo = [SELECT Id FROM Promotion__c WHERE Form_ID__c = :form.Id LIMIT 1];

        Test.startTest();
        SubUploadBatchUtils.populatePromo(subUpload, form.Id);
        Test.stopTest();

        Sub_Upload_Util__c updatedSubUpload = [SELECT Promo_ID__c FROM Sub_Upload_Util__c WHERE Id = :subUpload.Id];

        Assert.areEqual(promo.Id, updatedSubUpload.Promo_ID__c);
    }

    /************************************************************************************
     * Method: processAttachmentValidNoUS
     * APEX method tested : SubUploadBatchUtils.processAttachment
     * Description : Verifies that a TFR record is created for each line in the CSV File
     *************************************************************************************/
    @IsTest
    static void processAttachmentNoUS() {
        Sub_Upload_Util__c subUpload = [
            SELECT
                Mailing_List__r.TLA_ID__c,
                File_Source_Description__c,
                Promo_ID__c,
                Is_Crm_Generated__c,
                Mailing_List__c,
                DSP__c,
                OverwriteFanData__c,
                AcquisitionChannel__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];
        Form__c form = TestFactory.getForm(subUpload.Mailing_List__r.TLA_ID__c);
        form.Form_Name__c = subUpload.File_Source_Description__c;
        insert form;

        String gender = UtilConstants.VALID_GENDERS.iterator().next();
        String validCsvLine =
            'a@b.com,yes,,,,,A,B,12345,01/01/2000,09/09,' +
            gender +
            ',abAddress1,abCity,abState,AR,123,Spanish,ABFBPage,@ab';

        String invalidCsvLine =
            'x@y.com,yes,,,,,X,Y,999990,13/13/2000,11/11,' +
            gender +
            ',xyAddress1,xyCity,xyState,US,987,English,XYFBPage,@xy';

        List<List<String>> csvLines = new List<List<String>>();
        csvLines.add(validCsvLine.split(','));
        csvLines.add(invalidCsvLine.split(','));

        List<Temp_Form_Response__c> tfrRecords = new List<Temp_Form_Response__c>();
        Map<String, String> emailInvalidDOBmap = new Map<String, String>();

        Test.startTest();
        SubUploadBatchUtils.processAttachment(csvLines, tfrRecords, emailInvalidDOBmap, subUpload, false, form.Id);
        Test.stopTest();

        Assert.areEqual(2, tfrRecords.size());
        Assert.areEqual(1, emailInvalidDOBmap.size());

        Assert.areEqual('a@b.com', tfrRecords[0].Email__c);
        Assert.areEqual('A', tfrRecords[0].First_Name__c);
        Assert.areEqual('B', tfrRecords[0].Last_Name__c);
        Assert.areEqual('12345', tfrRecords[0].Mobile_Phone__c);
        Assert.areEqual(gender, tfrRecords[0].Gender__c);
        Assert.areEqual(Date.newInstance(2000, 1, 1), tfrRecords[0].birthday__c);
        Assert.areEqual(null, tfrRecords[0].birthday_mm_dd__c);
        Assert.areEqual(subUpload.Mailing_List__c, tfrRecords[0].MailingList_Array__c);
        Assert.areEqual(form.Id, tfrRecords[0].Form_ID__c);
        Assert.areEqual(UtilConstants.FILE_UPLOAD_TOOL, tfrRecords[0].Source__c);
        Assert.areEqual('abAddress1', tfrRecords[0].address_1__c);
        Assert.areEqual('abCity', tfrRecords[0].city__c);
        Assert.areEqual('abState', tfrRecords[0].state__c);
        Assert.areEqual('AR', tfrRecords[0].country_region__c);
        Assert.areEqual('123', tfrRecords[0].postal_code__c);
        Assert.areEqual('Spanish', tfrRecords[0].preferred_language__c);
        Assert.areEqual('ABFBPage', tfrRecords[0].facebook_page__c);
        Assert.areEqual('@ab', tfrRecords[0].twitter_handle__c);

        Assert.areEqual('x@y.com', tfrRecords[1].Email__c);
        Assert.areEqual('X', tfrRecords[1].First_Name__c);
        Assert.areEqual('Y', tfrRecords[1].Last_Name__c);
        Assert.areEqual('999990', tfrRecords[1].Mobile_Phone__c);
        Assert.areEqual(gender, tfrRecords[1].Gender__c);
        Assert.areEqual(null, tfrRecords[1].birthday__c);
        Assert.areEqual(null, tfrRecords[1].birthday_mm_dd__c);
        Assert.areEqual(subUpload.Mailing_List__c, tfrRecords[1].MailingList_Array__c);
        Assert.areEqual(form.Id, tfrRecords[1].Form_ID__c);
        Assert.areEqual(UtilConstants.FILE_UPLOAD_TOOL, tfrRecords[1].Source__c);
        Assert.areEqual('xyAddress1', tfrRecords[1].address_1__c);
        Assert.areEqual('xyCity', tfrRecords[1].city__c);
        Assert.areEqual('xyState', tfrRecords[1].state__c);
        Assert.areEqual('US', tfrRecords[1].country_region__c);
        Assert.areEqual('987', tfrRecords[1].postal_code__c);
        Assert.areEqual('English', tfrRecords[1].preferred_language__c);
        Assert.areEqual('XYFBPage', tfrRecords[1].facebook_page__c);
        Assert.areEqual('@xy', tfrRecords[1].twitter_handle__c);

        Assert.areEqual(new Set<String>{ 'x@y.com' }, emailInvalidDOBmap.keySet());
        Assert.areEqual(new List<String>{ '13/13/2000' }, emailInvalidDOBmap.values());
    }

    /************************************************************************************
     * Method: processAttachmentUS
     * APEX method tested : SubUploadBatchUtils.processAttachment
     * Description : Verifies that a TFR record is created for each line in the CSV File
     *************************************************************************************/
    @IsTest
    static void processAttachmentUS() {
        Sub_Upload_Util__c subUpload = [
            SELECT
                Mailing_List__r.TLA_ID__c,
                File_Source_Description__c,
                Promo_ID__c,
                Is_Crm_Generated__c,
                Mailing_List__c,
                DSP__c,
                OverwriteFanData__c,
                AcquisitionChannel__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];
        Form__c form = TestFactory.getForm(subUpload.Mailing_List__r.TLA_ID__c);
        form.Form_Name__c = subUpload.File_Source_Description__c;
        insert form;

        String gender = UtilConstants.VALID_GENDERS.iterator().next();
        String validCsvLine =
            'a@b.com,yes,,,,,A,B,12345,01/01/2000,09/09,' +
            gender +
            ',abAddress1,abCity,abState,AR,123,Spanish,ABFBPage,@ab';

        String invalidCsvLine1 =
            'x@y.com,yes,,,,,X,Y,999990,13/13/2000,11/11,' +
            gender +
            ',xyAddress1,xyCity,xyState,US,987,English,XYFBPage,@xy';

        String invalidCsvLine2 =
            'f@g.com,yes,,,,,F,G,999990,11/11/2000,88/11,' +
            gender +
            ',fgAddress1,fgCity,fgState,US,987,English,FGFBPage,@fg';
        List<List<String>> csvLines = new List<List<String>>();
        csvLines.add(validCsvLine.split(','));
        csvLines.add(invalidCsvLine1.split(','));
        csvLines.add(invalidCsvLine2.split(','));

        List<Temp_Form_Response__c> tfrRecords = new List<Temp_Form_Response__c>();
        Map<String, String> emailInvalidDOBmap = new Map<String, String>();

        Test.startTest();
        SubUploadBatchUtils.processAttachment(csvLines, tfrRecords, emailInvalidDOBmap, subUpload, true, form.Id);
        Test.stopTest();

        Assert.areEqual(3, tfrRecords.size());

        Assert.areEqual('a@b.com', tfrRecords[0].Email__c);
        Assert.areEqual('A', tfrRecords[0].First_Name__c);
        Assert.areEqual('B', tfrRecords[0].Last_Name__c);
        Assert.areEqual('12345', tfrRecords[0].Mobile_Phone__c);
        Assert.areEqual(gender, tfrRecords[0].Gender__c);
        Assert.areEqual(null, tfrRecords[0].birthday__c);
        Assert.areEqual('09/09', tfrRecords[0].birthday_mm_dd__c);
        Assert.areEqual(subUpload.Mailing_List__c, tfrRecords[0].MailingList_Array__c);
        Assert.areEqual(form.Id, tfrRecords[0].Form_ID__c);
        Assert.areEqual(UtilConstants.FILE_UPLOAD_TOOL, tfrRecords[0].Source__c);
        Assert.areEqual('abAddress1', tfrRecords[0].address_1__c);
        Assert.areEqual('abCity', tfrRecords[0].city__c);
        Assert.areEqual('abState', tfrRecords[0].state__c);
        Assert.areEqual('AR', tfrRecords[0].country_region__c);
        Assert.areEqual('123', tfrRecords[0].postal_code__c);
        Assert.areEqual('Spanish', tfrRecords[0].preferred_language__c);
        Assert.areEqual('ABFBPage', tfrRecords[0].facebook_page__c);
        Assert.areEqual('@ab', tfrRecords[0].twitter_handle__c);

        Assert.areEqual(2, emailInvalidDOBmap.size());
        Assert.isTrue(emailInvalidDOBmap.keySet().contains('x@y.com'));
        Assert.isTrue(emailInvalidDOBmap.keySet().contains('f@g.com'));
        Assert.areEqual('13/13/2000', emailInvalidDOBmap.get('x@y.com'));
        Assert.areEqual('88/11', emailInvalidDOBmap.get('f@g.com'));
    }

    /************************************************************************************
     * Method: createSubUploadFailureValidDOB
     * APEX method tested : SubUploadBatchUtils.createSubUploadFailure
     * Description : Verifies that a subUploadFailure record is created from a TFR
     *************************************************************************************/
    @IsTest
    static void createSubUploadFailureValidDOB() {
        Sub_Upload_Util__c subUpload = [
            SELECT Mailing_List__r.TLA_ID__c, File_Source_Description__c, Promo_ID__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];

        Temp_Form_Response__c tfr = new Temp_Form_Response__c(
            Email__c = 'a@b.com',
            First_Name__c = 'A',
            Last_Name__c = 'B',
            Birthday__c = Date.newInstance(2000, 1, 1),
            Twitter_Handle__c = '@ab',
            Facebook_Page__c = 'ABFbPage',
            Sub_Upload_Source__c = subUpload.Id,
            Gender__c = UtilConstants.VALID_GENDERS.iterator().next()
        );
        List<String> errors = new List<String>{ UtilConstants.FILE_UPLOAD_VALIDATION_HELD_EMAIL };

        Test.startTest();
        SubUploadFailures__c subUploadFailure = SubUploadBatchUtils.createSubUploadFailure(
            tfr,
            errors,
            null,
            'File1.csv'
        );
        Test.stopTest();

        Assert.areEqual(tfr.Email__c, subUploadFailure.Email__c);
        Assert.areEqual(tfr.First_Name__c, subUploadFailure.First_Name__c);
        Assert.areEqual(tfr.Last_Name__c, subUploadFailure.Last_Name__c);
        Assert.areEqual(String.valueOf(tfr.Birthday__c), subUploadFailure.Birthdate__c);
        Assert.areEqual(tfr.Twitter_Handle__c, subUploadFailure.Twitter_Handle__c);
        Assert.areEqual(tfr.Sub_Upload_Source__c, subUploadFailure.Upload_Id__c);
        Assert.areEqual(tfr.Gender__c, subUploadFailure.Gender__c);
        Assert.areEqual(UtilConstants.FILE_UPLOAD_VALIDATION_HELD_EMAIL, subUploadFailure.Failure_Reason__c);
        Assert.areEqual('File1.csv', subUploadFailure.Attachment__c);
    }

    /************************************************************************************
     * Method: createSubUploadFailureInvalidDOB
     * APEX method tested : SubUploadBatchUtils.createSubUploadFailure
     * Description : Verifies that a subUploadFailure record is created from a TFR
     *************************************************************************************/
    @IsTest
    static void createSubUploadFailureInvalidDOB() {
        Sub_Upload_Util__c subUpload = [
            SELECT Mailing_List__r.TLA_ID__c, File_Source_Description__c, Promo_ID__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];

        Temp_Form_Response__c tfr = new Temp_Form_Response__c(
            Email__c = 'a@b.com',
            First_Name__c = 'A',
            Last_Name__c = 'B',
            Birthday__c = null,
            Twitter_Handle__c = '@ab',
            Facebook_Page__c = 'ABFbPage',
            Sub_Upload_Source__c = subUpload.Id,
            Gender__c = UtilConstants.VALID_GENDERS.iterator().next()
        );
        List<String> errors = new List<String>{ UtilConstants.FILE_UPLOAD_VALIDATION_HELD_EMAIL };

        Test.startTest();
        SubUploadFailures__c subUploadFailure = SubUploadBatchUtils.createSubUploadFailure(
            tfr,
            errors,
            '13-13-2000',
            'File1.csv'
        );
        Test.stopTest();

        Assert.areEqual(tfr.Email__c, subUploadFailure.Email__c);
        Assert.areEqual(tfr.First_Name__c, subUploadFailure.First_Name__c);
        Assert.areEqual(tfr.Last_Name__c, subUploadFailure.Last_Name__c);
        Assert.areEqual('13-13-2000', subUploadFailure.Birthdate__c);
        Assert.areEqual(tfr.Twitter_Handle__c, subUploadFailure.Twitter_Handle__c);
        Assert.areEqual(tfr.Sub_Upload_Source__c, subUploadFailure.Upload_Id__c);
        Assert.areEqual(tfr.Gender__c, subUploadFailure.Gender__c);
        Assert.areEqual(UtilConstants.FILE_UPLOAD_VALIDATION_HELD_EMAIL, subUploadFailure.Failure_Reason__c);
        Assert.areEqual('File1.csv', subUploadFailure.Attachment__c);
    }

    /************************************************************************************
     * Method: validateTFRS
     * APEX method tested : SubUploadBatchUtils.validateTFRS
     * Description : Verifies that a subUploadFailure record is created from an invalid TFR
     *************************************************************************************/
    @IsTest
    static void validateTFRS() {
        Sub_Upload_Util__c subUpload = [
            SELECT Mailing_List__r.TLA_ID__c, File_Source_Description__c, Promo_ID__c
            FROM Sub_Upload_Util__c
            LIMIT 1
        ];

        Temp_Form_Response__c validTFR = new Temp_Form_Response__c(
            Email__c = 'a@b.com',
            First_Name__c = 'A',
            Last_Name__c = 'B',
            Birthday__c = null,
            Twitter_Handle__c = '@ab',
            Facebook_Page__c = 'ABFbPage',
            Sub_Upload_Source__c = subUpload.Id,
            Gender__c = UtilConstants.VALID_GENDERS.iterator().next()
        );

        Held_Email__c heldEmail = new Held_Email__c(Email__c = 'x@y.com');
        insert heldEmail;
        Map<String, String> emailInvalidDOBmap = new Map<String, String>();
        emailInvalidDOBmap.put('x@y.com', '99-99-99');

        Temp_Form_Response__c invalidTFR1 = new Temp_Form_Response__c(
            Email__c = 'x@y.com',
            Gender__c = 'INVALID_GENRE'
        );
        Temp_Form_Response__c invalidTFR2 = new Temp_Form_Response__c(Gender__c = 'INVALID_GENRE');

        Temp_Form_Response__c invalidTFR3 = new Temp_Form_Response__c(Email__c = '@sonymusic.com');
        Temp_Form_Response__c invalidTFR4 = new Temp_Form_Response__c(
            Email__c = 'some@email.com',
            Mobile_Phone__c = '99999999999999999999999999999999999999999999',
            Postal_Code__c = '99999999999999999999999999999999999999999999'
        );
        List<Temp_Form_Response__c> tfrs = new List<Temp_Form_Response__c>{
            validTFR,
            invalidTFR1,
            invalidTFR2,
            invalidTFR3,
            invalidTFR4
        };
        List<SubUploadFailures__c> subUploadFailures = new List<SubUploadFailures__c>();

        Test.startTest();
        List<Temp_Form_Response__c> validTFRs = SubUploadBatchUtils.validateTFRS(
            tfrs,
            subUploadFailures,
            emailInvalidDOBmap,
            'File1.csv'
        );
        Test.stopTest();

        Assert.areEqual(1, validTFRs.size());
        Assert.areEqual(4, subUploadFailures.size());
        Assert.areEqual('a@b.com', validTFRs.get(0).Email__c);
        Assert.areEqual(
            String.join(
                new List<String>{
                    UtilConstants.REST_RESPONSE_ERROR_INVALID_GENDER,
                    UtilConstants.FILE_UPLOAD_VALIDATION_HELD_EMAIL,
                    UtilConstants.FILE_UPLOAD_VALIDATION_INVALID_DOB
                },
                ','
            ),
            subUploadFailures.get(0).Failure_Reason__c
        );
        Assert.areEqual(
            String.join(
                new List<String>{
                    UtilConstants.REST_RESPONSE_ERROR_INVALID_GENDER,
                    UtilConstants.REST_RESPONSE_ERROR_EMPTY_EMAIL
                },
                ','
            ),
            subUploadFailures.get(1).Failure_Reason__c
        );
        Assert.areEqual(UtilConstants.REST_RESPONSE_ERROR_INVALID_EMAIL, subUploadFailures.get(2).Failure_Reason__c);
        Assert.areEqual(
            UtilConstants.REST_RESPONSE_ERROR_STRING_TOO_LONG + ' [mobile_phone__c, postal_code__c]',
            subUploadFailures.get(3).Failure_Reason__c
        );
    }
}