public with sharing class DoTempFormResponseTriggerHelper {

    /**
     * PRE-EXISTING Method (Not Reviewed)
     * @description Gathers the DO_Temp_Form_Response__c record ids
     * @param  newDoTempFormResponses DO_Temp_Form_Response__c records from Trigger.new
     */
    public static void onAfterInsert(DO_Temp_Form_Response__c[] newDoTempFormResponses) {
        Set<ID> newDoTempFormResponsesIDs = new Set<ID>();
        for (DO_Temp_Form_Response__c obj : newDoTempFormResponses) {
            newDoTempFormResponsesIDs.add(obj.Id);
        }
        createTriggeredSend1(newDoTempFormResponsesIDs);
    }

    /** 
     * PRE-EXISTING Method (Not Reviewed)
     * @description Performs a callout to marketing cloud to create a TriggeredSend
     * @param  newDoTempFormResponsesIDs1 List of DO TFR Ids
     */
    @future(callout=true)
    public static void createTriggeredSend1(Set<ID> newDoTempFormResponsesIDs1) {
        List<ID> listIds = new List<ID>(newDoTempFormResponsesIDs1);
        String responseStatus = '';
        List<DO_Temp_Form_Response__c> newDOTempFormResponseList = new List<DO_Temp_Form_Response__c>();
        List<DO_Temp_Form_Response__c> DoTempformResponseList = [
            SELECT
                Id,
                Email__c,
                First_Name__c,
                Welcome_Email_Delivered__c,
                CreatedDate,
                Form_ID__c,
                triggered_send_definition_key__c,
                Parent_MID__c,
                Temp_Form_Response_Created__c
            FROM DO_Temp_Form_Response__c
            WHERE
                Id IN :listIds
                AND Form_ID__c != NULL
                AND triggered_send_definition_key__c != NULL
                AND Parent_MID__c != NULL
                AND Temp_Form_Response_Created__c = FALSE
        ];

        system.debug('PRIME-DoTempformResponseList:' + DoTempformResponseList);
        if (!DoTempformResponseList.isEmpty()) {
            for (DO_Temp_Form_Response__c newFormResponse : DoTempformResponseList) {
                Http h = new Http();
                HttpRequest req = new HttpRequest();
                req.setMethod('POST');
                req.setHeader('SOAPAction', 'Create');
                req.setHeader('Content-Type', 'text/xml;charset=UTF-8');

                String userName = ConfigUtils.getConfigString(ConfigUtils.MC_CREDENTIALS_USER);
                String password = ConfigUtils.getConfigString(ConfigUtils.MC_CREDENTIALS_PASSWORD);

                String customerKey = '';
                String encryptedKey = '';
                String email = '';
                String clientID = '';
                String firstName = '';
                String subscriberKey = '';
                if (newFormResponse.Form_ID__c != null) {
                    if (newFormResponse.Parent_MID__c != null && newFormResponse.Parent_MID__c != '') {
                        clientID = newFormResponse.Parent_MID__c;
                        system.debug('FormResponseQueueableProcess1 ClientID: ' + clientID);
                    }

                    if (
                        newFormResponse.triggered_send_definition_key__c != null &&
                        newFormResponse.triggered_send_definition_key__c != ''
                    ) {
                        customerKey = newFormResponse.triggered_send_definition_key__c;
                        system.debug('FormResponseQueueableProcess1 customerKey: ' + customerKey);
                    }
                }

                if (newFormResponse.Email__c != null) {
                    subscriberKey = newFormResponse.Id;
                    if (newFormResponse.Email__c != null && newFormResponse.Email__c != '') {
                        email = newFormResponse.Email__c;
                    }
                }
                if (newFormResponse.First_Name__c != null) {
                    firstName = newFormResponse.First_Name__c;
                }
                system.debug('QUEAPEX newFormResponse:' + newFormResponse);
                system.debug('QUEAPEX clientID:' + clientID);
                system.debug('QUEAPEX customerKey:' + customerKey);
                system.debug('QUEAPEX subscriberKey:' + subscriberKey);
                system.debug('QUEAPEX email:' + email);

                String xml =
                    '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
                    '<Header><Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>' +
                    userName +
                    '</Username>' +
                    '<Password>' +
                    password +
                    '</Password></UsernameToken></Security></Header><Body><CreateRequest xmlns="http://exacttarget.com/wsdl/partnerAPI"><Options>' +
                    '<RequestType>Asynchronous</RequestType></Options><Objects xsi:type="TriggeredSend"><Client><ID>' +
                    clientID +
                    '</ID></Client><PartnerKey xsi:nil="true" />' +
                    '<ObjectID xsi:nil="true" /><TriggeredSendDefinition><PartnerKey xsi:nil="true" /><ObjectID xsi:nil="true" /><CustomerKey>' +
                    customerKey +
                    '</CustomerKey>' +
                    '</TriggeredSendDefinition><Subscribers><PartnerKey xsi:nil="true" /><ObjectID xsi:nil="true" /><EmailAddress>' +
                    email +
                    '</EmailAddress>' +
                    '<SubscriberKey>' +
                    subscriberKey +
                    '</SubscriberKey></Subscribers></Objects>' +
                    '</CreateRequest></Body></Envelope>';
                req.setBody(xml);

                //req.setEndpoint('https://webservice.s6.exacttarget.com/Service.asmx');
                req.setEndpoint(ConfigUtils.getConfigString(ConfigUtils.MC_ENDPOINT_BASE));

                string bodyRes = '';
                HttpResponse res = new HttpResponse();
                try {
                    if (!Test.isRunningTest()) {
                        res = h.send(req);
                    }
                    if (!Test.isRunningTest()) {
                        bodyRes = res.getBody();
                    } else {
                        bodyRes = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><soap:Header><wsa:Action>CreateResponse</wsa:Action><wsa:MessageID>urn:uuid:d61a73f7-36d5-4065-abc0-98dcf5a75fd8</wsa:MessageID><wsa:RelatesTo>urn:uuid:86dd4f47-867f-4c88-9ec4-0023652f5e9c</wsa:RelatesTo><wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To><wsse:Security><wsu:Timestamp wsu:Id="Timestamp-2e80ed6d-0439-46e3-a8ed-9165357b0540"><wsu:Created>2016-05-07T02:35:51Z</wsu:Created><wsu:Expires>2016-05-07T02:40:51Z</wsu:Expires></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><CreateResponse xmlns="http://exacttarget.com/wsdl/partnerAPI"><Results xsi:type="TriggeredSendCreateResult"><StatusCode>OK</StatusCode><StatusMessage>Queued</StatusMessage><OrdinalID>0</OrdinalID><NewID>0</NewID></Results><RequestID>a7cb3b8e-2ef5-432e-91da-66fcba302304</RequestID><OverallStatus>OK</OverallStatus></CreateResponse></soap:Body></soap:Envelope>';
                    }
                } catch (System.CalloutException e) {
                    System.debug('Calloutor: ' + e);
                    //ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, e.getMessage()));
                }
                if (bodyRes.contains('OK')) {
                    System.debug('inside OK');
                    responseStatus = 'OK';
                }
                if (responseStatus == 'OK') {
                    newFormResponse.Welcome_Email_Delivered__c = true;
                    newFormResponse.MC_Error_Message__c = '';
                    System.debug('inside OK1');
                } else {
                    newFormResponse.MC_Error_Message__c = 'Error';
                    System.debug('inside error');
                }
                newDOTempFormResponseList.add(newFormResponse);
                System.debug('Request:' + xml);
                System.debug('Response:' + bodyRes);
            }
        }
        TriggerControl.disableTrigger(DOTempFormResponseTriggerHandler.SELF);
        update newDOTempFormResponseList;
        TriggerControl.enableTrigger(DOTempFormResponseTriggerHandler.SELF);
    }

    /**
     * @description Upserts fan retarget records based on DO TFR
     * @param  doTFRs    doTFRs DO TFRs from Trigger.new
     * @param  formsById Form ID as key and respective form record as value
     */
    public static void upsertFanRetarget(List<DO_Temp_Form_Response__c> doTFRs, Map<Id, Form__c> formsById) {
        Set<String> fanEmails = new Set<String>();
        List<DO_Temp_Form_Response__c> retargetDOTFRs = new List<DO_Temp_Form_Response__c>();
        List<String> retargetingTerritories = System.Label.Retarget_Territories.split(',');
        Set<String> doTFRTerritories = new Set<String>();

        for (DO_Temp_Form_Response__c doTFR : doTFRs) {
            Form__c form = formsById.get(doTFR.Form_ID__c);
            String territoryName = form.TLA_ID__r.Territory_Id__r.Territory__c;

            if (doTFR.Is_Retargeting_Form_Response__c && retargetingTerritories.contains(territoryName)) {
                fanEmails.add(doTFR.Email__c);
                retargetDOTFRs.add(doTFR);
                doTFRTerritories.add(territoryName);
            }
        }

        if (!retargetDOTFRs.isEmpty()) {
            Map<String, Fan__c> fansByEmail = new Map<String, Fan__c>();
            for (Fan__c fan : [SELECT Id, Email__c FROM Fan__c WHERE Email__c IN :fanEmails]) {
                fansByEmail.put(fan.Email__c, fan);
            }

            if (!fansByEmail.isEmpty()) {
                Set<String> subsFanTerritoryKey = new Set<String>();
                for (AggregateResult ar : [
                    SELECT Fan_ID__r.Email__c Email, Mailing_List_ID__r.TLA_ID__r.Territory_ID__c Territory
                    FROM Subscription__c
                    WHERE
                        Fan_ID__r.Email__c IN :fanEmails
                        AND Active__c = TRUE
                        AND Mailing_List_ID__r.TLA_ID__r.Territory_ID__r.Territory__c IN :doTFRTerritories
                    GROUP BY Fan_ID__r.Email__c, Mailing_List_ID__r.TLA_ID__r.Territory_ID__c
                ]) {
                    String key = String.valueOf(ar.get('Email')) + String.valueOf(ar.get('Territory'));
                    subsFanTerritoryKey.add(key);
                }

                if (!subsFanTerritoryKey.isEmpty()) {
                    Map<String, Fan_Retarget__c> retargetsByFanTerritoryKey = new Map<String, Fan_Retarget__c>();
                    for (Fan_Retarget__c fanRetarget : [
                        SELECT
                            Id,
                            Retargeting_Consent__c,
                            Retargeting_Source_Campaign__c,
                            Retargeting_Consent_Acquired_Date__c,
                            Territory_ID__c,
                            Fan_ID__r.Email__c
                        FROM Fan_Retarget__c
                        WHERE
                            Fan_ID__r.Email__c IN :fansByEmail.keySet()
                            AND Territory_ID__r.Territory__c IN :doTFRTerritories
                    ]) {
                        String key = fanRetarget.Fan_ID__r.Email__c + fanRetarget.Territory_ID__c;
                        retargetsByFanTerritoryKey.put(key, fanRetarget);
                    }

                    Map<String, Fan_Retarget__c> fanRetargetsToUpsert = new Map<String, Fan_Retarget__c>();

                    for (DO_Temp_Form_Response__c doTFR : retargetDOTFRs) {
                        Form__c form = formsById.get(doTFR.Form_ID__c);
                        String key = doTFR.Email__c + form?.TLA_ID__r?.Territory_ID__c;

                        if (
                            fansByEmail.containsKey(doTFR.Email__c) &&
                            subsFanTerritoryKey.contains(key) &&
                            !fanRetargetsToUpsert.containsKey(key)
                        ) {
                            Fan_Retarget__c fanRetarget = retargetsByFanTerritoryKey.containsKey(key)
                                ? retargetsByFanTerritoryKey.get(key)
                                : new Fan_Retarget__c();

                            if (!fanRetarget.Retargeting_Consent__c) {
                                fanRetarget.Retargeting_Consent__c = true;
                                fanRetarget.Retargeting_Source_Campaign__c = form.Id;
                                fanRetarget.Retargeting_Consent_Acquired_Date__c = System.now();
                                fanRetarget.Territory_ID__c = form.TLA_ID__r.Territory_Id__c;
                                fanRetarget.Fan_ID__c = fansByEmail.get(doTFR.Email__c).Id;
                                fanRetargetsToUpsert.put(key, fanRetarget);
                            }
                        }
                    }

                    if (!fanRetargetsToUpsert.isEmpty()) {
                        upsert fanRetargetsToUpsert.values();
                    }
                }
            }
        }
    }

    /**
     * @description Creates a TFR from a DO TFR when it is approved
     * @param  doTFRs DO Temp Form Responses from Trigger.new
     */
    public static void createTFRFromDOTFR(List<DO_Temp_Form_Response__c> doTFRs) {
        List<DO_Temp_Form_Response__c> approvedDOTFRs = new List<DO_Temp_Form_Response__c>();

        for (DO_Temp_Form_Response__c doTFR : doTFRs) {
            if (doTFR.Approved__c && !doTFR.Temp_Form_Response_Created__c) {
                approvedDOTFRs.add(doTFR);
            }
        }

        List<Temp_Form_Response__c> tfrsToInsert = new List<Temp_Form_Response__c>();
        List<DO_Temp_Form_Response__c> doTFRsToUpdate = new List<DO_Temp_Form_Response__c>();

        if (!approvedDOTFRs.isEmpty()) {
            List<String> fieldMapping = UtilConstants.DO_TFR_DIRECT_MAPPING;

            for (DO_Temp_Form_Response__c doTFR : approvedDOTFRs) {
                Temp_Form_Response__c tfr = new Temp_Form_Response__c();

                for (String field : fieldMapping) {
                    if (doTFR.get(field) != null) {
                        tfr.put(field, doTFR.get(field));
                    }
                }
                doTFR.Temp_Form_Response_Created__c = true;
                tfr.MailingList_Array__c = doTFR.MailingList__c;
                tfrsToInsert.add(tfr);
                doTFRsToUpdate.add(doTFR);
            }

            insert tfrsToInsert;
        }
    }

    /**
     * @description Updates triggered_send_definition_key__c and Parent_MID__c fields on the DO TFR
     * @param  doTFRs DO TFRs from Trigger.new
     */
    public static void updateTSDKandParentMID(List<DO_Temp_Form_Response__c> doTFRs) {
        Map<String, FormMLTriggerSendMapping__c> mapFormIdMLid = new Map<String, FormMLTriggerSendMapping__c>();
        Map<Id, FormMLTriggerSendMapping__c> mapFormIdMLdefault = new Map<Id, FormMLTriggerSendMapping__c>();
        Map<Id, FormMLTriggerSendMapping__c> mapFormIdMLdefaultForAllML = new Map<Id, FormMLTriggerSendMapping__c>();
        Set<Id> formIds = new Set<Id>();

        for (DO_Temp_Form_Response__c doTFR : doTFRs) {
            formIds.add(doTFR.Form_ID__c);
        }

        for (FormMLTriggerSendMapping__c formML : [
            SELECT
                Id,
                Mailing_List_ID__c,
                TriggeredSendDefinitionKey__c,
                MC_MID__c,
                Form_ID__c,
                DefaultTriggerSendFlag__c,
                UseDefaultTrigDefForAllMailingLists__c
            FROM FormMLTriggerSendMapping__c
            WHERE Form_ID__c IN :formIds AND Active__c = TRUE
        ]) {
            if (formML.DefaultTriggerSendFlag__c) {
                mapFormIdMLdefault.put(formML.Form_ID__c, formML);
            }
            if (formML.UseDefaultTrigDefForAllMailingLists__c) {
                mapFormIdMLdefaultForAllML.put(formML.Form_ID__c, formML);
            }
            if (formML.Mailing_List_ID__c != null) {
                mapFormIdMLid.put(formML.Form_ID__c + '|' + formML.Mailing_List_ID__c, formML);
            }
        }

        for (DO_Temp_Form_Response__c doTFR : doTFRs) {
            FormMLTriggerSendMapping__c formML;
            if (doTFR.mailinglist__c == null) {
                formML = mapFormIdMLdefault.get(doTFR.Form_ID__c);
                if (formML != null) {
                    doTFR.triggered_send_definition_key__c = formML.TriggeredSendDefinitionKey__c;
                    doTFR.Parent_MID__c = formML.MC_MID__c;
                } else {
                    doTFR.addError(UtilConstants.REST_RESPONSE_ERROR_DO_NO_TRIGGER);
                }
            } else {
                formML = mapFormIdMLdefaultForAllML.containsKey(doTFR.Form_ID__c)
                    ? mapFormIdMLdefaultForAllML.get(doTFR.Form_ID__c)
                    : mapFormIdMLid.get(doTFR.Form_ID__c + '|' + doTFR.mailinglist__c);
                if (formML != null) {
                    doTFR.triggered_send_definition_key__c = formML.TriggeredSendDefinitionKey__c;
                    doTFR.Parent_MID__c = formML.MC_MID__c;
                } else {
                    doTFR.addError(UtilConstants.REST_RESPONSE_ERROR_DO_NO_TRIGGER);
                }
            }
        }
    }
}