/**
 * @description Builds CLM-ready JSON payload for Appraiser Case with related Deficiencies.
 * Used to transform Salesforce data into DocuSign CLM merge field structure.
 */
public class AppraiserCasePayloadBuilder {
    
    /**
     * @description Generates CLM merge payload for a given Appraiser Case.
     * @param caseId Appraiser_Case__c record Id
     * @return Map<String, Object> CLM merge data ready for template rendering
     */
    public static Map<String, Object> buildPayload(String caseId) {
        // Query parent case with all child deficiencies
        Appraiser_Case__c appraiserCase = queryAppraiserCase(caseId);
        
        if (appraiserCase == null) {
            throw new IllegalArgumentException('Appraiser Case not found: ' + caseId);
        }
        
        // Build CLM payload structure
        Map<String, Object> payload = new Map<String, Object>();
        payload.put('AppraiserCaseNumber', appraiserCase.Name);
        payload.put('AppraiserFieldReviewDate', formatDate(appraiserCase.Appraiser_Field_Review_Date__c));
        payload.put('LetterSentDate', formatDate(appraiserCase.Letter_Sent_Date__c));
        payload.put('FHACaseNumber', appraiserCase.FHA_Case_Number__c);
        payload.put('AppraiserName', appraiserCase.Appraiser_Name__c);
        payload.put('AppraiserSalutation', appraiserCase.Appraiser_Salutation__c);
        payload.put('AppraiserLastName', appraiserCase.Appraiser_Last_Name__c);
        payload.put('AppraiserEmail', appraiserCase.Appraiser_Email__c);
        payload.put('AppraiserStreet', appraiserCase.Appraiser_Street__c);
        payload.put('AppraiserCity', appraiserCase.Appraiser_City__c);
        payload.put('AppraiserStateProvince', appraiserCase.Appraiser_State_Province__c);
        payload.put('AppraiserPostalCode', appraiserCase.Appraiser_Postal_Code__c);
        payload.put('AppraiserCountry', appraiserCase.Appraiser_Country__c);
        payload.put('AppraiserAddress', formatMailingAddress(
            appraiserCase.Appraiser_Street__c,
            appraiserCase.Appraiser_City__c,
            appraiserCase.Appraiser_State_Province__c,
            appraiserCase.Appraiser_Postal_Code__c,
            appraiserCase.Appraiser_Country__c
        ));
        payload.put('PropertyStreet', appraiserCase.Property_Street__c);
        payload.put('PropertyCity', appraiserCase.Property_City__c);
        payload.put('PropertyStateProvince', appraiserCase.Property_State_Province__c);
        payload.put('PropertyPostalCode', appraiserCase.Property_Postal_Code__c);
        payload.put('PropertyCountry', appraiserCase.Property_Country__c);
        payload.put('PropertyAddress', formatAddress(appraiserCase));
        
        // Transform child deficiencies into DeficiencyList array
        List<Map<String, Object>> deficiencyList = new List<Map<String, Object>>();
        if (appraiserCase.Deficiencies__r != null && !appraiserCase.Deficiencies__r.isEmpty()) {
            for (Appraiser_Case_Deficiency__c deficiency : appraiserCase.Deficiencies__r) {
                Map<String, Object> defMap = new Map<String, Object>();
                defMap.put('deficiencyNumber', deficiency.Deficiency_Number__c);
                defMap.put('description', deficiency.Description__c);
                defMap.put('resolution', deficiency.Resolution__c);
                defMap.put('reference', deficiency.Reference__c);
                deficiencyList.add(defMap);
            }
        }
        payload.put('DeficiencyList', deficiencyList);
        
        return payload;
    }
    
    /**
     * @description Returns CLM payload as JSON string for API transmission.
     * @param caseId Appraiser_Case__c record Id
     * @return String JSON representation of payload
     */
    public static String buildPayloadJson(String caseId) {
        Map<String, Object> payload = buildPayload(caseId);
        return JSON.serialize(payload);
    }
    
    /**
     * @description Query Appraiser Case with related Deficiencies ordered by number.
     * @param caseId Appraiser_Case__c record Id
     * @return Appraiser_Case__c Record with Deficiencies__r populated
     */
    private static Appraiser_Case__c queryAppraiserCase(String caseId) {
        List<Appraiser_Case__c> results = [
            SELECT 
                Id, 
                Name, 
                Appraiser_Field_Review_Date__c, 
                Letter_Sent_Date__c,
                FHA_Case_Number__c,
                Appraiser_Name__c,
                Appraiser_Salutation__c,
                Appraiser_Last_Name__c,
                Appraiser_Email__c,
                Appraiser_Street__c,
                Appraiser_City__c,
                Appraiser_State_Province__c,
                Appraiser_Postal_Code__c,
                Appraiser_Country__c,
                Property_Street__c,
                Property_City__c,
                Property_State_Province__c,
                Property_Postal_Code__c,
                Property_Country__c,
                (SELECT Id, Deficiency_Number__c, Description__c, Resolution__c, Reference__c 
                 FROM Deficiencies__r 
                 ORDER BY Deficiency_Number__c ASC)
            FROM Appraiser_Case__c
            WHERE Id = :caseId
            LIMIT 1
        ];
        
        return results.isEmpty() ? null : results.get(0);
    }
    
    /**
     * @description Format date for CLM merge (for example Apr 09, 2026) or null.
     * @param dt Date field value
     * @return String Formatted date or null
     */
    private static String formatDate(Date dt) {
        return dt != null
            ? DateTime.newInstance(dt, Time.newInstance(0, 0, 0, 0)).format('MMM dd, yyyy')
            : null;
    }

    private static String formatAddress(Appraiser_Case__c appraiserCase) {
        return formatMailingAddress(
            appraiserCase.Property_Street__c,
            appraiserCase.Property_City__c,
            appraiserCase.Property_State_Province__c,
            appraiserCase.Property_Postal_Code__c,
            appraiserCase.Property_Country__c
        );
    }

    public static String formatMailingAddress(
        String street,
        String city,
        String stateProvince,
        String postalCode,
        String country
    ) {
        List<String> lines = new List<String>();
        if (String.isNotBlank(street)) {
            lines.add(street.trim());
        }

        List<String> localityParts = new List<String>();
        if (String.isNotBlank(city)) {
            localityParts.add(city.trim());
        }
        if (String.isNotBlank(stateProvince)) {
            localityParts.add(stateProvince.trim());
        }

        String locality = String.join(localityParts, ', ');
        if (String.isNotBlank(postalCode)) {
            locality = String.isNotBlank(locality)
                ? locality + ' ' + postalCode.trim()
                : postalCode.trim();
        }
        if (String.isNotBlank(locality)) {
            lines.add(locality);
        }

        if (String.isNotBlank(country)) {
            lines.add(country.trim());
        }

        return lines.isEmpty() ? null : String.join(lines, ', ');
    }
}
