/***********************************************************************************************************
 * Name         : ExportBatchTest
 * Purpose      : Test class for ExportBatch
 **********************************************************************************************************/

@isTest
private class ExportBatchTest {
    @TestSetup
    static void makeData() {
        TLA__c tla = TestFactory.createTerritoryLabelArtist();
        Form__c form = TestFactory.getForm(tla.Id);
        form.Form_Name__c = 'Form Name';
        insert form;
        Mailing_List__c mailingList = TestFactory.createMailingList('Mailing List Test', tla.Id);

        Fan__c fan = new Fan__c(
            Name = 'Test Fan 1',
            Email__c = 'testfan1@mail.com',
            City__c = 'Montevideo',
            Address_1__c = '123, Elm Street',
            Birthdate__c = Date.parse('01/01/1985')
        );

        Fan__c secondFan = new Fan__c(
            Name = 'Test Fan 2',
            Email__c = 'testfan2@mail.com',
            City__c = 'Buenos Aires',
            Address_1__c = '456, Another Street',
            Birthdate__c = Date.parse('02/02/2000')
        );
        insert new List<Fan__c>{ fan, secondFan };

        Form_Response__c formResponse = new Form_Response__c(
            Form_Id__c = form.Id,
            Fan_Id__c = fan.Id,
            First_Name__c = fan.Name,
            Address_1__c = fan.Address_1__c,
            Birthday__c = fan.Birthdate__c,
            City__c = fan.City__c,
            Email__c = fan.Email__c
        );
        Form_Response__c secondFormResponse = new Form_Response__c(
            Form_Id__c = form.Id,
            Fan_Id__c = secondFan.Id,
            First_Name__c = secondFan.Name,
            Address_1__c = secondFan.Address_1__c,
            Birthday__c = secondFan.Birthdate__c,
            City__c = secondFan.City__c,
            Email__c = secondFan.Email__c
        );

        insert new List<Form_Response__c>{ formResponse, secondFormResponse };

        Promotion__c promotion = TestFactory.createPromotion(tla.Id, form.Id);
        Subscription__c subscription = TestFactory.createSubscription(fan.Id, true, mailingList.Id, promotion.Id);
        Subscription_History__c subHistory = TestFactory.getSubscriptionHistory(
            fan.Id,
            subscription.Id,
            mailingList.Id,
            UtilConstants.SH_ACTION_SIGN_UP,
            null,
            false
        );
        subHistory.Promo_ID__c = promotion.Id;
        insert subHistory;
    }

    /************************************************************************************
     * Method: executeFormResponse
     * APEX method tested : ExportBatch.execute
     * Description : Verifies that a Form Response Export is processed successfully
     *************************************************************************************/
    @IsTest
    static void executeFormResponse() {
        Form__c form = [SELECT Id FROM Form__c LIMIT 1];
        String query = 'SELECT Form_Id__r.Form_Name__c, Email__c, City__c, Birthday__c, Address_1__c, Address_2__c FROM Form_Response__c';
        Export__c exportRecord = new Export__c(
            Export_Type__c = 'Form Response',
            Query__c = query,
            Form_ID__c = form.Id
        );
        insert exportRecord;

        String artistName = TestFactory.DEFAULT_ARTIST_NAME;
        List<String> fieldList = new List<String>{
            'Email__c',
            'City__c',
            'Birthday__c',
            'Address_1__c',
            'Address_2__c'
        };
        String objName = 'Form_Response__c';

        Test.startTest();
        ExportBatch batchClass = new ExportBatch(artistName, exportRecord, fieldList, objName);

        Database.executeBatch(batchClass);
        Test.stopTest();

        Export__c updatedExport = [
            SELECT Is_ready_to_download__c, Exported_Record_Count__c
            FROM Export__c
            WHERE Id = :exportRecord.Id
        ];
        System.assertEquals(true, updatedExport.Is_ready_to_download__c);
        System.assertEquals(2, updatedExport.Exported_Record_Count__c);

        List<Attachment> attachments = [SELECT Id, Body FROM Attachment WHERE ParentId = :exportRecord.Id];
        System.assertEquals(1, attachments.size());

        Blob b = attachments[0].Body;
        String fileContent = b.toString();
        List<String> lines = fileContent.split('\n');
        System.assertEquals(3, lines.size());
        System.assertEquals('Email,City,Birthday,Address 1,Address 2', lines.get(0));
        System.assertEquals('testfan1@mail.com,Montevideo,01/01/1985,"123, Elm Street",', lines.get(1));
        System.assertEquals('testfan2@mail.com,Buenos Aires,02/02/2000,"456, Another Street",', lines.get(2));
    }

    /************************************************************************************
     * Method: executeMailingListSubHistory
     * APEX method tested : ExportBatch.execute
     * Description : Verifies that a Subscription History Export is processed successfully
     *************************************************************************************/
    @IsTest
    static void executeMailingListSubHistory() {
        String query = 'SELECT Id, Subscription_ID__c, Promo_ID__r.Name, Fan_ID__r.Email__c, Fan_ID__r.City__c,Fan_ID__r.Birthdate__c FROM Subscription_History__c';
        Export__c exportRecord = new Export__c(Export_Type__c = 'Mailing List', Query__c = query);
        insert exportRecord;

        String artistName = TestFactory.DEFAULT_ARTIST_NAME;
        List<String> fieldList = new List<String>{
            'Fan_ID__r.Email__c',
            'Fan_ID__r.City__c',
            'Fan_ID__r.Birthdate__c'
        };
        String objName = 'Subscription_History__c';

        Test.startTest();
        ExportBatch batchClass = new ExportBatch(artistName, exportRecord, fieldList, objName);
        Database.executeBatch(batchClass);
        Test.stopTest();

        Export__c updatedExport = [
            SELECT Is_ready_to_download__c, Exported_Record_Count__c
            FROM Export__c
            WHERE Id = :exportRecord.Id
        ];
        System.assertEquals(true, updatedExport.Is_ready_to_download__c);
        System.assertEquals(1, updatedExport.Exported_Record_Count__c);

        List<Attachment> attachments = [SELECT Id, Body FROM Attachment WHERE ParentId = :exportRecord.Id];
        System.assertEquals(1, attachments.size());

        Blob b = attachments[0].Body;
        String fileContent = b.toString();
        List<String> lines = fileContent.split('\n');
        System.assertEquals(2, lines.size());
        System.assertEquals('Email,City,Birthdate', lines.get(0));
        System.assertEquals('testfan1@mail.com,Montevideo,01/01/1985', lines.get(1));
    }

    /************************************************************************************
     * Method: multipleAttachments
     * APEX method tested : ExportBatch.execute
     * Description : Verifies that a new attachment is created when the CSV String exceeds
     *  MAX_THRESHOLD to avoid String length exceeds maximum: 6000000 error
     *************************************************************************************/
    @IsTest
    static void multipleAttachments() {
        Form__c form = [SELECT Id FROM Form__c LIMIT 1];
        String query = 'SELECT Form_Id__r.Form_Name__c, Email__c, City__c, Birthday__c, Address_1__c, Address_2__c FROM Form_Response__c';
        Export__c exportRecord = new Export__c(
            Export_Type__c = 'Form Response',
            Query__c = query,
            Form_ID__c = form.Id
        );
        insert exportRecord;

        String artistName = TestFactory.DEFAULT_ARTIST_NAME;
        List<String> fieldList = new List<String>{
            'Email__c',
            'City__c',
            'Birthday__c',
            'Address_1__c',
            'Address_2__c'
        };
        String objName = 'Form_Response__c';

        List<Form_Response__c> scope = Database.query(query + ' WHERE Email__c = \'testfan1@mail.com\'');

        Test.startTest();
        ExportBatch batchClass = new ExportBatch(artistName, exportRecord, fieldList, objName);
        batchClass.MAX_THRESHOLD = 10;
        batchClass.execute(null, scope);
        scope = Database.query(query + ' WHERE Email__c = \'testfan2@mail.com\'');
        batchClass.execute(null, scope);
        Test.stopTest();

        List<Attachment> attachments = [SELECT Id, Body FROM Attachment WHERE ParentId = :exportRecord.Id ORDER BY CreatedDate ASC];
        System.assertEquals(2, attachments.size());

        Blob b = attachments[0].Body;
        String fileContent = b.toString();
        List<String> lines = fileContent.split('\n');
        System.assertEquals(2, lines.size());
        System.assertEquals('Email,City,Birthday,Address 1,Address 2', lines.get(0));
        System.assertEquals('testfan1@mail.com,Montevideo,01/01/1985,"123, Elm Street",', lines.get(1));

        b = attachments[1].Body;
        fileContent = b.toString();
        lines = fileContent.split('\n');
        System.assertEquals(2, lines.size());
        System.assertEquals('Email,City,Birthday,Address 1,Address 2', lines.get(0));
        System.assertEquals('testfan2@mail.com,Buenos Aires,02/02/2000,"456, Another Street",', lines.get(1));
    }

    /************************************************************************************
     * Method: finishException
     * APEX method tested : ExportBatch.finish
     * Description : Verifies that the exceptions thrown in the finish method are logged
     *************************************************************************************/
    @IsTest
    static void finishException() {
        Export__c exportRecord = new Export__c(Export_Type__c = 'Form Response', Query__c = null, Form_ID__c = null);
        String objName = 'Form_Response__c';
        String artistName = TestFactory.DEFAULT_ARTIST_NAME;
        List<String> fieldList = new List<String>{
            'Email__c',
            'City__c',
            'Birthday__c',
            'Address_1__c',
            'Address_2__c'
        };

        Test.startTest();
        ExportBatch batchClass = new ExportBatch(artistName, exportRecord, fieldList, objName);
        batchClass.finish(null);
        Test.stopTest();

        System.assertEquals(1, Database.countQuery('SELECT count() FROM Apex_Error_Log__c'));
    }
}
