/**
 * @description Handles request validation and envelope JSON building for Docusign composite envelopes
 * @author Paul Huliganga
 * @date 2026-02-25
 */
global with sharing class DocusignEnvelopeRequestHandler {
    
    /**
     * @description Validates composite envelope request parameters
     * @param req Request object to validate
     * @throws IllegalArgumentException if validation fails
     */
    public static void validateRequest(DocusignEnvelopeRequest req) {
        if (req.templateIds == null || req.templateIds.isEmpty()) {
            throw new IllegalArgumentException('At least one template ID is required');
        }
        
        if (req.templateIds.size() > 14) {
            throw new IllegalArgumentException('Maximum 14 templates allowed per envelope');
        }
        
        if (String.isBlank(req.recordId)) {
            throw new IllegalArgumentException('Salesforce record ID is required');
        }
        
        // Check for null template IDs
        for (String templateId : req.templateIds) {
            if (String.isBlank(templateId)) {
                throw new IllegalArgumentException('Template ID cannot be blank');
            }
        }
    }
    
    /**
     * @description Builds composite envelope JSON for Docusign API from request
     * @param req Request object containing parameters
     * @return JSON string for Docusign API request
     */
    public static String buildEnvelopeJSON(DocusignEnvelopeRequest req) {
        // Remove duplicates and sort alphabetically
        List<String> sortedTemplateIds = sortTemplatesAlphabetically(
            new Set<String>(req.templateIds)
        );
        
        // Build composite envelope JSON
        return buildCompositeEnvelopeJSON(
            sortedTemplateIds,
            req.recordId,
            req.language,
            req.emailSubject,
            null  // customFields not supported in InvocableVariable (Phase 2 enhancement)
        );
    }
    
    /**
     * @description Removes duplicates and sorts template IDs alphabetically
     * @param templateIdSet Set of template IDs
     * @return Sorted list of unique template IDs
     */
    private static List<String> sortTemplatesAlphabetically(Set<String> templateIdSet) {
        List<String> sortedList = new List<String>(templateIdSet);
        sortedList.sort();
        return sortedList;
    }
    
    /**
     * @description Builds composite envelope JSON for Docusign API
     * @param templateIds List of template IDs to combine
     * @param recordId Salesforce record ID for custom fields
     * @param language Language code (en/es)
     * @param emailSubject Email subject line
     * @param customFields Map of custom field name/value pairs
     * @return JSON string for Docusign API request
     */
    private static String buildCompositeEnvelopeJSON(
        List<String> templateIds,
        String recordId,
        String language,
        String emailSubject,
        Map<String, String> customFields
    ) {
        // Build composite templates array
        List<Object> compositeTemplates = new List<Object>();
        
        Integer sequence = 1;
        for (String templateId : templateIds) {
            Map<String, Object> compositeTemplate = new Map<String, Object>{
                'compositeTemplateId' => String.valueOf(sequence),
                'serverTemplates' => new List<Object>{
                    new Map<String, Object>{
                        'sequence' => String.valueOf(sequence),
                        'templateId' => templateId
                    }
                }
            };
            
            // Add custom fields if this is the first template
            if (sequence == 1 && (String.isNotBlank(recordId) || customFields != null)) {
                compositeTemplate.put('inlineTemplates', buildInlineTemplates(recordId, language, customFields));
            }
            
            compositeTemplates.add(compositeTemplate);
            sequence++;
        }
        
        // Build envelope object
        Map<String, Object> envelope = new Map<String, Object>{
            'status' => 'sent',
            'emailSubject' => String.isNotBlank(emailSubject) 
                ? emailSubject 
                : 'Please review and sign these forms',
            'compositeTemplates' => compositeTemplates
        };
        
        return JSON.serialize(envelope);
    }
    
    /**
     * @description Builds inline templates for custom fields
     * @param recordId Salesforce record ID
     * @param language Language code
     * @param customFields Additional custom fields
     * @return List of inline template objects
     */
    private static List<Object> buildInlineTemplates(
        String recordId,
        String language,
        Map<String, String> customFields
    ) {
        List<Object> textCustomFields = new List<Object>();
        
        // Add Salesforce record ID
        if (String.isNotBlank(recordId)) {
            textCustomFields.add(new Map<String, Object>{
                'name' => 'SalesforceRecordId',
                'value' => recordId,
                'show' => 'false',
                'required' => 'false'
            });
        }
        
        // Add language
        if (String.isNotBlank(language)) {
            textCustomFields.add(new Map<String, Object>{
                'name' => 'Language',
                'value' => language,
                'show' => 'false',
                'required' => 'false'
            });
        }
        
        // Add additional custom fields
        if (customFields != null && !customFields.isEmpty()) {
            for (String fieldName : customFields.keySet()) {
                textCustomFields.add(new Map<String, Object>{
                    'name' => fieldName,
                    'value' => customFields.get(fieldName),
                    'show' => 'false',
                    'required' => 'false'
                });
            }
        }
        
        return new List<Object>{
            new Map<String, Object>{
                'sequence' => '1',
                'customFields' => new Map<String, Object>{
                    'textCustomFields' => textCustomFields
                }
            }
        };
    }
}
