/***********************************************************************************************************
 * Name         : SubscriptionHistoryTriggerHelper
 * Purpose      : Trigger helper class to hold the logic for Subscription History records
 **********************************************************************************************************/
public without sharing class SubscriptionHistoryTriggerHelper {
    /**
     * @description Retrieves the Subscriptions related to the current SubHistories
     * @param subscriptionHistories subscriptionHistory list
     * @return Map<Id, Subscription>
     */
    public static Map<Id, Subscription__c> getSubscriptions(List<Subscription_History__c> subscriptionHistories) {
        Set<Id> subIds = new Set<Id>();
        for (Subscription_History__c subHistory : subscriptionHistories) {
            if (String.isNotEmpty(subHistory.Subscription_ID__c)) {
                subIds.add(subHistory.Subscription_ID__c);
            }
        }

        Map<Id, Subscription__c> subscriptionMap = new Map<Id, Subscription__c>(
            [
                SELECT
                    Id,
                    Is_Crm_Generated__c,
                    Active__c,
                    Preferred_Genre__c,
                    Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c,
                    Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__r.Territory__c,
                    Fan_ID__c
                FROM Subscription__c
                WHERE Id IN :subIds
            ]
        );
        return subscriptionMap;
    }

    /**
     * @description Updates Subscription Preferred_Genre__c, Active__c and Is_Crm_Generated__c fields
     * @param subscriptionHistories subscriptionHistory list
     * @param subsMap related Subscriptions Map
     */
    public static void updateSubscription(
        List<Subscription_History__c> subscriptionHistories,
        Map<Id, Subscription__c> subsMap
    ) {
        Map<Id, Subscription__c> subscriptionMapToUpdate = new Map<Id, Subscription__c>();
        for (Subscription_History__c subHistory : subscriptionHistories) {
            if (String.isNotEmpty(subHistory.Subscription_ID__c)) {
                Subscription__c oldSub = subsMap.get(subHistory.Subscription_ID__c);
                Subscription__c newSub = new Subscription__c();

                newSub.Id = oldSub.Id;
                newSub.Active__c = oldSub.Active__c;
                newSub.Preferred_Genre__c = oldSub.Preferred_Genre__c;
                newSub.Is_Crm_Generated__c = oldSub.Is_Crm_Generated__c;

                newSub.Active__c = subHistory.Action__c != UtilConstants.SH_ACTION_UNSUB;

                if (subHistory.Action__c == UtilConstants.SH_ACTION_SIGN_UP) {
                    if (subHistory.Is_Crm_Generated__c && !oldSub.Active__c) {
                        newSub.Is_Crm_Generated__c = true;
                    } else if (!subHistory.Is_Crm_Generated__c) {
                        newSub.Is_Crm_Generated__c = false;
                    }
                }

                List<String> genres = String.isNotEmpty(subHistory.Preferred_Genre__c)
                    ? (subHistory.Preferred_Genre__c).toUpperCase().split(';')
                    : new List<String>();

                if (!genres.isEmpty()) {
                    FormatUtils.addToMultiValueField(newSub, 'Preferred_Genre__c', genres);
                }

                if (
                    oldSub.Active__c != newSub.Active__c ||
                    oldSub.Is_Crm_Generated__c != newSub.Is_Crm_Generated__c ||
                    oldSub.Preferred_Genre__c != newSub.Preferred_Genre__c
                ) {
                    subscriptionMapToUpdate.put(subHistory.Subscription_ID__c, newSub);
                }
            }
        }

        if (!subscriptionMapToUpdate.isEmpty()) {
            update subscriptionMapToUpdate.values();
        }
    }

    /**
     * @description Updates fanRetarget.Retargeting_Consent__c to false if the there are no more active
     *  subscriptions for the territory the Fan is unsubscribing
     * @param subscriptionHistories subscriptionHistory list
     * @param subsMap related Subscriptions Map
     */
    public static void updateFanRetargetsByUnsubscriptions(
        List<Subscription_History__c> subscriptionHistories,
        Map<Id, Subscription__c> subsMap
    ) {
        Set<Id> territories = new Set<Id>();
        Set<Id> fanIds = new Set<Id>();
        List<String> retargetTerritories = ConfigUtils.getConfigMultipleStrings(ConfigUtils.RETARGET_TERRITORIES);
        Map<Id, Set<Id>> mapFanTerrWithSubs = new Map<Id, Set<Id>>();
        List<Subscription_History__c> unsubHistories = new List<Subscription_History__c>();

        for (Subscription_History__c subHistory : subscriptionHistories) {
            if (
                String.isNotBlank(subHistory.Subscription_ID__c) &&
                subHistory.Action__c == UtilConstants.SH_ACTION_UNSUB &&
                retargetTerritories.contains(
                    subsMap.get(subHistory.Subscription_ID__c)
                        .Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__r.Territory__c
                )
            ) {
                fanIds.add(subHistory.Fan_ID__c);
                territories.add(
                    subsMap.get(subHistory.Subscription_ID__c).Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c
                );
                unsubHistories.add(subHistory);
            }
        }
        if (!unsubHistories.isEmpty()) {
            for (Subscription__c sub : [
                SELECT
                    Id,
                    Fan_ID__c,
                    Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c
                FROM Subscription__c
                WHERE
                    Fan_ID__c IN :fanIds
                    AND Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c IN :territories
                    AND Active__c = TRUE
                    AND Id NOT IN :subsMap.keySet()
            ]) {
                Set<Id> territorySet = mapFanTerrWithSubs.get(sub.Fan_ID__c);
                if (territorySet == null) {
                    territorySet = new Set<Id>{ sub.Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c };
                } else {
                    territorySet.add(sub.Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c);
                }
                mapFanTerrWithSubs.put(sub.Fan_ID__c, territorySet);
            }

            Map<Id, Set<Id>> mapFanTerrWithoutSubs = new Map<Id, Set<Id>>();
            for (Subscription_History__c subH : unsubHistories) {
                Subscription__c sub = subsMap.get(subH.Subscription_ID__c);
                Set<Id> mapTerritorySub = mapFanTerrWithSubs.get(subH.Fan_ID__c);
                if (
                    mapTerritorySub == null ||
                    !mapTerritorySub.contains(sub.Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c)
                ) {
                    if (mapFanTerrWithoutSubs.containsKey(sub.Fan_ID__c)) {
                        mapFanTerrWithoutSubs.get(sub.Fan_ID__c)
                            .add(sub.Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c);
                    } else {
                        mapFanTerrWithoutSubs.put(
                            sub.Fan_ID__c,
                            new Set<Id>{ sub.Mailing_List_ID__r.TLA_ID__r.TL_ID__r.Territory_ID__c }
                        );
                    }
                }
            }
            if (!mapFanTerrWithoutSubs.isEmpty()) {
                updateFanRetargets(mapFanTerrWithoutSubs, territories);
            }
        }
    }

    /**
     * @description Updates the Retargeting_Consent__c to false and the Retargeting_Consent_Disabled_Date__c
     *  if the fan id and territory related to the fan retarget are included in mapFanTerritories
     * @param mapFanTerritories Map<Id, Set<Id>>  Key: Fan ID - Value: Territory IDs
     */
    private static void updateFanRetargets(Map<Id, Set<Id>> mapFanTerritories, Set<Id> territories) {
        List<Fan_Retarget__c> fanRetargetsToUpdate = new List<Fan_Retarget__c>();

        for (Fan_Retarget__c fanRetarget : [
            SELECT ID, Fan_ID__c, Territory_ID__c
            FROM Fan_Retarget__c
            WHERE
                Fan_ID__c IN :mapFanTerritories.keySet()
                AND Territory_ID__c IN :territories
                AND Retargeting_Consent__c = TRUE
        ]) {
            if (mapFanTerritories.get(fanRetarget.Fan_ID__c).contains(fanRetarget.Territory_ID__c)) {
                fanRetarget.Retargeting_Consent__c = false;
                fanRetarget.Retargeting_Consent_Disabled_Date__c = System.now();
                fanRetargetsToUpdate.add(fanRetarget);
            }
        }
        if (!fanRetargetsToUpdate.isEmpty()) {
            update fanRetargetsToUpdate;
        }
    }
}
