/***********************************************************************************************************
 * Name         : FanMCAllContactsCleanupBatch
 * Purpose      : Job to process Fan_MC_Cleanup__c records, sending delete requests to Marketing Cloud.
 **********************************************************************************************************/
public with sharing class FanMCAllContactsCleanupBatch implements Database.Batchable<sObject>, Database.Allowscallouts, Database.Stateful, Schedulable, Database.RaisesPlatformEvents {
    private Integer MAX_BATCH_SIZE = ConfigUtils.getConfigInt(ConfigUtils.MC_CONTACT_DELETE_BATCH_SIZE);
    private Integer daysToProcess;

    public MarketingCloudHelper.MarketingCloudAuthResponseWrapper authResponseWrapper;

    public List<Fan_MC_Cleanup__c> failedRecords = new List<Fan_MC_Cleanup__c>();
    public List<Fan_MC_Cleanup__c> fansToIntegrate = new List<Fan_MC_Cleanup__c>();
    public Integer remainingRecords;

    public FanMCAllContactsCleanupBatch() {
        this.daysToProcess = 1;
    }

    public FanMCAllContactsCleanupBatch(Integer daysToProcess) {
        this.daysToProcess = daysToProcess > 99999 ? 99999 : daysToProcess;
    }

    public Database.QueryLocator start(Database.BatchableContext BC) {
        String baseQuery =
            ' FROM Fan_MC_Cleanup__c WHERE Delete_Request_Triggered__c = FALSE AND Operation_ID__c = NULL AND Is_Deleted_From_MC_All_Subscribers__c = FALSE AND CreatedDate >= LAST_N_DAYS:' +
            daysToProcess;
        String countQuery = 'SELECT count() ' + baseQuery;
        String query = 'SELECT Id, Fan_Id__c, MC_Error_Message__c ' + baseQuery;
        remainingRecords = Database.countQuery(countQuery);
        return Database.getQueryLocator(query);
    }

    public void execute(Database.BatchableContext BC, List<Fan_MC_Cleanup__c> scope) {
        List<Fan_MC_Cleanup__c> recordsToUpdate = new List<Fan_MC_Cleanup__c>();
        if (
            fansToIntegrate.size() + scope.size() <= MAX_BATCH_SIZE &&
            fansToIntegrate.size() + scope.size() != remainingRecords
        ) {
            fansToIntegrate.addAll(scope);
        } else {
            authResponseWrapper = MarketingCloudHelper.getTokenForContactsDelete(authResponseWrapper);

            List<Fan_MC_Cleanup__c> accumulatedFans = new List<Fan_MC_Cleanup__c>();
            for (Fan_MC_Cleanup__c value : scope) {
                if (fansToIntegrate.size() < MAX_BATCH_SIZE) {
                    fansToIntegrate.add(value);
                } else {
                    accumulatedFans.add(value);
                }
            }
            recordsToUpdate.addAll(
                FanMCAllContactsCleanupBatchHelper.sendRequests(
                    fansToIntegrate,
                    authResponseWrapper.authResponse.access_token
                )
            );
            remainingRecords -= fansToIntegrate.size();
            fansToIntegrate = accumulatedFans;

            if (fansToIntegrate.size() == remainingRecords && remainingRecords > 0) {
                recordsToUpdate.addAll(
                    FanMCAllContactsCleanupBatchHelper.sendRequests(
                        fansToIntegrate,
                        authResponseWrapper.authResponse.access_token
                    )
                );
            }
            for (Fan_MC_Cleanup__c fanMC : recordsToUpdate) {
                if (fanMC.MC_Error_Message__c != null) {
                    failedRecords.add(fanMC);
                }
            }
            update recordsToUpdate;
        }
    }

    public void finish(Database.BatchableContext BC) {
        BatchJobUtils.sendEmail(
            ConfigUtils.SET_SUPPORT_EMAIL,
            ConfigUtils.MC_CONTACT_DELETE_SENDER,
            ConfigUtils.MC_CONTACT_DELETE_BATCH_SUBJECT,
            ConfigUtils.MC_CONTACT_DELETE_EMAIL_BODIES,
            'failedRecords.csv',
            failedRecords
        );
    }

    public void execute(SchedulableContext sc) {
        Database.executeBatch(new FanMCAllContactsCleanupBatch(), 2000);
    }

    public static void schedule() {
        BatchJobUtils.scheduleJob(
            new FanMCAllContactsCleanupBatch(),
            ConfigUtils.getConfigString(ConfigUtils.MC_CONTACT_DELETE_CRON_EXP)
        );
    }
}
