/***********************************************************************************************************
 * Name         : CA_ServiceTrackerApprovalEmail
 * Purpose      : Scheduled job to send reminder emails to approvers for pending Service Tracker approvals.
 **********************************************************************************************************/
public without sharing class CA_ServiceTrackerApprovalEmail implements Schedulable {

    private static final String ORG_BASE_URL = URL.getOrgDomainURL().toExternalForm();
    private static final Integer MILLISECONDS_IN_DAY = 86400000;

    private static final String DAYS_GREEN_BACKGROUND_COLOR = '#90EE90';
    private static final Integer DAYS_YELLOW_BACKGROUND = ConfigUtils.getConfigInt(ConfigUtils.CA_ST_PENDING_ALERT_YELLOW);
    private static final String DAYS_YELLOW_BACKGROUND_COLOR = '#EDEA80';
    private static final Integer DAYS_RED_BACKGROUND = ConfigUtils.getConfigInt(ConfigUtils.CA_ST_PENDING_ALERT_RED);
    private static final String DAYS_RED_BACKGROUND_COLOR = '#F6AAAA';

    private static final Set<String> EXCLUDED_OPP_STAGES = new Set<String>{
        CA_Constants.OPPORTUNITY_STAGE_SIGNED,
        CA_Constants.OPPORTUNITY_STAGE_ACTIVE_IN_OA,
        CA_Constants.OPPORTUNITY_STAGE_QC_COMPLETE,
        CA_Constants.OPPORTUNITY_STAGE_COMPLETE
    };

    public void execute(SchedulableContext sc) {
        try {
            List<Opportunity_Right__c> pendingServices = [
                SELECT
                    Id,
                    Request_Time__c,
                    Opportunity__c,
                    Opportunity__r.Name,
                    Master_Right__c,
                    Master_Right__r.Name,
                    Master_Right__r.Approver__c,
                    Master_Right__r.Approver__r.FirstName,
                    Master_Right__r.Approver__r.LastName,
                    Master_Right__r.Additional_Recipients__c
                FROM Opportunity_Right__c
                WHERE Approval_Status__c = :CA_ServiceTrackerHelper.STATUS_PENDING_APPROVAL
                AND Master_Right__r.Active__c = TRUE
                AND Master_Right__r.Approver__c != NULL
                AND Opportunity__r.StageName NOT IN :EXCLUDED_OPP_STAGES
                ORDER BY Request_Time__c ASC
            ];

            if (pendingServices.isEmpty()) {
                return;
            }

            Map<Id, String> approverNameById = new Map<Id, String>();
            Map<Id, Set<String>> ccByApprover = new Map<Id, Set<String>>();
            Map<Id, List<Opportunity_Right__c>> servicesByApprover = new Map<Id, List<Opportunity_Right__c>>();
            Set<Id> processedMasterRights = new Set<Id>();

            for (Opportunity_Right__c service : pendingServices) {
                Id masterRightId = service.Master_Right__c;
                Id approverId = service.Master_Right__r.Approver__c;

                if (!approverNameById.containsKey(approverId)) {
                    approverNameById.put(approverId, service.Master_Right__r.Approver__r.FirstName ?? service.Master_Right__r.Approver__r.LastName);
                    ccByApprover.put(approverId, new Set<String>());
                    servicesByApprover.put(approverId, new List<Opportunity_Right__c>());
                }

                servicesByApprover.get(approverId).add(service);

                if (processedMasterRights.add(masterRightId)) {
                    String additionalRecipients = service.Master_Right__r.Additional_Recipients__c;
                    if (String.isNotBlank(additionalRecipients)) {
                        for (String emailAddress : additionalRecipients.split('[;,]')) {
                            String normalizedEmail = emailAddress.trim().toLowerCase();
                            if (String.isNotBlank(normalizedEmail)) {
                                ccByApprover.get(approverId).add(normalizedEmail);
                            }
                        }
                    }
                }
            }

            EmailTemplate template = [
                SELECT Id, Subject, HtmlValue
                FROM EmailTemplate
                WHERE DeveloperName = 'CA_ApprovalReminderEmailNotification'
                LIMIT 1
            ];

            String serviceUrl = ORG_BASE_URL + CA_ServiceTrackerHelper.ST_HUB_URL;

            List<Messaging.SingleEmailMessage> emails = new List<Messaging.SingleEmailMessage>();

            for (Id approverId : ccByApprover.keySet()) {
                List<String> ccRecipients = new List<String>();
                for (String emailAddress : ccByApprover.get(approverId)) {
                    EmailUtils.addRecipient(ccRecipients, emailAddress);
                }

                Map<String, String> replaceMap = new Map<String, String>{
                    '{{APPROVER_FIRST_NAME}}' => approverNameById.get(approverId),
                    '{{ST_HUB_URL}}' => serviceUrl,
                    '{{SERVICE_COUNT}}' => String.valueOf(servicesByApprover.get(approverId).size()),
                    '{{PENDING_APPROVALS_TABLE}}' => buildPendingApprovalsTable(servicesByApprover.get(approverId))
                };

                String subject = template.Subject;
                String htmlBody = template.HtmlValue;

                for (String key : replaceMap.keySet()) {
                    subject = subject.replace(key, replaceMap.get(key));
                    htmlBody = htmlBody.replace(key, replaceMap.get(key));
                }

                Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
                msg.setTargetObjectId(approverId);
                if (!ccRecipients.isEmpty()) {
                    msg.setCcAddresses(ccRecipients);
                }
                msg.setSaveAsActivity(false);
                msg.setSubject(subject);
                msg.setHtmlBody(htmlBody);

                emails.add(msg);
            }

            if (!emails.isEmpty()) {
                Messaging.sendEmail(emails, false);
            }
        } catch (Exception ex) {
            ErrorLogger.logError(ex);
        }
    }

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

    /**
     * @description Builds an HTML table of pending approval services.
     * @param pendingApprovals List of Opportunity_Right__c records.
     * @return HTML string with the formatted table, or an empty string if there are no services pending approval.
     */
    private static String buildPendingApprovalsTable(List<Opportunity_Right__c> pendingApprovals) {
        if (pendingApprovals == null || pendingApprovals.isEmpty()) {
            return '';
        }

        List<String> tableRows = new List<String>();
        Datetime now = Datetime.now();

        for (Opportunity_Right__c service : pendingApprovals) {
            Integer daysPendingApproval = (Integer)((now.getTime() - service.Request_Time__c.getTime()) / MILLISECONDS_IN_DAY);
            String oppUrl = ORG_BASE_URL + '/' + service.Opportunity__c;
            String daysBackgroundColor = (
                daysPendingApproval >= DAYS_RED_BACKGROUND ? DAYS_RED_BACKGROUND_COLOR : 
                (daysPendingApproval >= DAYS_YELLOW_BACKGROUND ? DAYS_YELLOW_BACKGROUND_COLOR : 
                DAYS_GREEN_BACKGROUND_COLOR)
            );

            tableRows.add(
                '<tr>' +
                    '<td style="background-color: ' + daysBackgroundColor + ';">' +
                        service.Master_Right__r.Name +
                    '</td>' +
                    '<td style="text-align: center; background-color: ' + daysBackgroundColor + ';">' +
                        service.Request_Time__c.date().format() +
                    '</td>' +
                    '<td style="text-align: center; background-color: ' + daysBackgroundColor + ';">' +
                        String.valueOf(daysPendingApproval) +
                    '</td>' +
                    '<td style="background-color: ' + daysBackgroundColor + ';">' +
                        '<a href="' + oppUrl + '">' +
                            service.Opportunity__r.Name +
                        '</a>' +
                    '</td>' +
                '</tr>'
            );
        }

        return
            '<table role="presentation" style="font-family: Arial, sans-serif; font-size: 12px; width: auto; white-space: nowrap; text-align: center;" border="1" cellpadding="5" cellspacing="0">' +
                '<thead>' +
                    '<tr>' +
                        '<th>Service Name</th>' +
                        '<th align="center">Requested Date</th>' +
                        '<th align="center">Days Pending Approval</th>' +
                        '<th>Opportunity</th>' +
                    '</tr>' +
                '</thead>' +
                '<tbody>' + String.join(tableRows, '') + '</tbody>' +
            '</table>';
    }
}