public class CLMDocGenCallout {

    // S1 demo environment
    private static final String CLM_ACCOUNT_ID_S1  = '2371cf36-eb8a-43fe-9f28-b5bbe7644397';
    private static final String CLM_BASE_S1         = 'callout:CLMNamedCred/v2/'         + CLM_ACCOUNT_ID_S1;

    // UAT demo environment
    private static final String CLM_ACCOUNT_ID_UAT = 'bccae332-c7db-4892-ab85-257df0f70fea';
    private static final String CLM_BASE_UAT        = 'callout:CLMuatNamedCreds/v2/'     + CLM_ACCOUNT_ID_UAT;

    private static final Integer HTTP_TIMEOUT = 30000;

    /** Resolve the correct CLM base URL. env: 'UAT' or 'S1'. */
    private static String clmBase(String env) {
        return env == 'S1' ? CLM_BASE_S1 : CLM_BASE_UAT;
    }

    /** Defaults to UAT environment. */
    public static CLMDocGenResponse generateDocument(
        String caseId,
        String templateDocHref,
        String destinationFolderHref,
        String destinationDocName
    ) {
        return generateDocument(caseId, templateDocHref, destinationFolderHref, destinationDocName, 'UAT');
    }

    /**
     * Generate a merged document via CLM documentxmlmergetasks (no user interaction).
     * @param caseId                Appraiser_Case__c record Id
     * @param templateDocHref       Full CLM Href URL of the template .docx document
     * @param destinationFolderHref Full CLM Href URL of the destination folder
     * @param destinationDocName    Filename for the generated document, e.g. "Review_AC-00001.docx"
     * @param env                   'UAT' (apiuatna11.springcm.com) or 'S1' (api.s1.us.clm.demo.docusign.net)
     */
    public static CLMDocGenResponse generateDocument(
        String caseId,
        String templateDocHref,
        String destinationFolderHref,
        String destinationDocName,
        String env
    ) {
        Map<String, Object> casePayload = AppraiserCasePayloadBuilder.buildPayload(caseId);

        Map<String, Object> requestBody = new Map<String, Object>{
            'TemplateDocument' => new Map<String, Object>{
                'Href' => templateDocHref
            },
            'DataXML'                 => buildDataXml(casePayload),
            'DestinationDocumentName' => destinationDocName,
            'DestinationFolder'       => new Map<String, Object>{
                'Href' => destinationFolderHref
            }
        };

        HttpRequest req = new HttpRequest();
        req.setEndpoint(clmBase(env) + '/documentxmlmergetasks');
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setTimeout(HTTP_TIMEOUT);
        req.setBody(JSON.serialize(requestBody));

        try {
            Http http = new Http();
            HttpResponse res = http.send(req);
            return parseTaskResponse(res);
        } catch (Exception ex) {
            return new CLMDocGenResponse(false, 'HTTP Callout Error: ' + ex.getMessage(), null, null);
        }
    }

    /** Poll the status of a submitted merge task by its GUID. */
    /** Poll the status of a submitted merge task by its GUID (defaults to UAT). */
    public static CLMDocGenResponse getTaskStatus(String taskId) {
        return getTaskStatus(taskId, 'UAT');
    }

    public static CLMDocGenResponse getTaskStatus(String taskId, String env) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(clmBase(env) + '/documentxmlmergetasks/' + taskId);
        req.setMethod('GET');
        req.setTimeout(HTTP_TIMEOUT);
        try {
            Http http = new Http();
            HttpResponse res = http.send(req);
            return parseTaskResponse(res);
        } catch (Exception ex) {
            return new CLMDocGenResponse(false, 'HTTP Callout Error: ' + ex.getMessage(), null, null);
        }
    }

    /** Probe any CLM resource path for debugging. env: 'UAT' or 'S1'. */
    public static String probe(String resource) {
        return probe(resource, 'UAT');
    }

    public static String probe(String resource, String env) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(clmBase(env) + '/' + resource);
        req.setMethod('GET');
        req.setTimeout(HTTP_TIMEOUT);
        HttpResponse res = new Http().send(req);
        return 'HTTP ' + res.getStatusCode() + ': ' + res.getBody();
    }

    /**
     * Build the DataXML string from the case payload.
     * Flat fields become direct child elements of <TemplateFieldData>.
     * DeficiencyList items expand into numbered elements:
     *   Deficiency_1_Number, Deficiency_1_Description, Deficiency_1_Resolution, etc.
     */
    private static String buildDataXml(Map<String, Object> payload) {
        String xml = '<TemplateFieldData>';

        // Emit flat fields first
        for (String key : payload.keySet()) {
            if (key == 'DeficiencyList') continue;
            xml += '<' + key + '>' + escapeXml(String.valueOf(payload.get(key))) + '</' + key + '>';
        }

        // Emit DeficiencyList as a nested list so templates can iterate dynamically
        List<Object> deficiencies = (List<Object>) payload.get('DeficiencyList');
        if (deficiencies != null && !deficiencies.isEmpty()) {
            xml += '<DeficiencyList>';
            for (Integer i = 0; i < deficiencies.size(); i++) {
                Map<String, Object> d = (Map<String, Object>) deficiencies[i];
                xml += '<Deficiency>';
                xml += '<Number>'      + escapeXml(String.valueOf(d.get('deficiencyNumber'))) + '</Number>';
                xml += '<Description>' + escapeXml(String.valueOf(d.get('description')))      + '</Description>';
                xml += '<Resolution>'  + escapeXml(String.valueOf(d.get('resolution')))       + '</Resolution>';
                xml += '</Deficiency>';
            }
            xml += '</DeficiencyList>';
            xml += '<DeficiencyCount>' + deficiencies.size() + '</DeficiencyCount>';
        }

        xml += '</TemplateFieldData>';
        return xml;
    }

    private static String escapeXml(String s) {
        if (s == null) return '';
        return s.replace('&', '&amp;')
                .replace('<', '&lt;')
                .replace('>', '&gt;')
                .replace('"', '&quot;')
                .replace('\'', '&apos;');
    }

    private static CLMDocGenResponse parseTaskResponse(HttpResponse res) {
        Integer statusCode = res.getStatusCode();
        String body = res.getBody();
        if (statusCode >= 200 && statusCode < 300) {
            Map<String, Object> m = (Map<String, Object>) JSON.deserializeUntyped(body);
            String href   = (String) m.get('Href');
            String status = (String) m.get('Status');
            String taskId = href != null ? href.substringAfterLast('/') : null;
            return new CLMDocGenResponse(true, 'Task status: ' + status, href, taskId);
        } else {
            return new CLMDocGenResponse(false, 'CLM API Error (HTTP ' + statusCode + '): ' + body, null, null);
        }
    }

    public class CLMDocGenResponse {
        public Boolean success;
        public String message;
        public String documentUrl;
        public String documentId;

        public CLMDocGenResponse(Boolean success, String message, String documentUrl, String documentId) {
            this.success     = success;
            this.message     = message;
            this.documentUrl = documentUrl;
            this.documentId  = documentId;
        }
    }
}
