/**
 * PdfGeneratorService
 *
 * Apex class to generate PDFs using the DataToPDF API.
 * This service calls the external API endpoint to generate PDFs from templates.
 *
 * Usage:
 *   // Generate PDF for an Account record
 *   String apiKey = 'pk_your_api_key';
 *   PdfGeneratorService.PdfResult result = PdfGeneratorService.generatePdf(apiKey, 'template_id', accountId);
 *   if (result.success) {
 *       // result.pdfBase64 contains the PDF data
 *       // result.contentType is 'application/pdf'
 *   } else {
 *       System.debug('Error: ' + result.errorMessage);
 *   }
 *
 *   // Generate and save PDF as a file attached to a record
 *   Id contentVersionId = PdfGeneratorService.generateAndSavePdf(apiKey, 'template_id', accountId, 'Invoice.pdf');
 *
 * Setup:
 *   1. Add https://datatopdf.app to Remote Site Settings
 */
public with sharing class PdfGeneratorService {

    // API Configuration, you can also put it in Custom Settings/Metadata to manage it more easily
    // Or through Named Credentials if preferred
    private static final String API_ENDPOINT = 'https://datatopdf.app/api/v1/pdf/generate';

    // Timeout in milliseconds (max 120 seconds for Salesforce callouts)
    private static final Integer CALLOUT_TIMEOUT = 120000;

    /**
     * Result wrapper class for PDF generation
     */
    public class PdfResult {
        @AuraEnabled public Boolean success { get; set; }
        @AuraEnabled public String pdfBase64 { get; set; }
        @AuraEnabled public String contentType { get; set; }
        @AuraEnabled public String errorMessage { get; set; }
        @AuraEnabled public String errorCode { get; set; }

        public PdfResult() {
            this.success = false;
        }
    }

    /**
     * Request wrapper class for API call
     */
    private class PdfRequest {
        public String templateId;
        public String recordId;

        public PdfRequest(String templateId, String recordId) {
            this.templateId = templateId;
            this.recordId = recordId;
        }
    }

    /**
     * Response wrapper class for API response
     */
    private class PdfResponse {
        public String pdf;
        public String contentType;
        public String error;
        public String code;
    }

    /**
     * Generate a PDF from a template and record
     *
     * @param apiKey The API key for authentication
     * @param templateId The ID of the PDF template to use
     * @param recordId The Salesforce record ID to fetch data from
     * @return PdfResult containing the generated PDF or error details
     */
    public static PdfResult generatePdf(String apiKey, String templateId, Id recordId) {
        PdfResult result = new PdfResult();

        // Validate inputs
        if (String.isBlank(apiKey)) {
            result.errorMessage = 'API key is required';
            result.errorCode = 'INVALID_REQUEST';
            return result;
        }

        if (String.isBlank(templateId)) {
            result.errorMessage = 'Template ID is required';
            result.errorCode = 'INVALID_REQUEST';
            return result;
        }

        if (recordId == null) {
            result.errorMessage = 'Record ID is required';
            result.errorCode = 'INVALID_REQUEST';
            return result;
        }

        try {
            // Build request
            PdfRequest requestBody = new PdfRequest(templateId, String.valueOf(recordId));
            String jsonBody = JSON.serialize(requestBody);

            // Make HTTP callout
            HttpRequest req = new HttpRequest();
            req.setEndpoint(API_ENDPOINT);
            req.setMethod('POST');
            req.setHeader('Content-Type', 'application/json');
            req.setHeader('X-API-Key', apiKey);
            req.setBody(jsonBody);
            req.setTimeout(CALLOUT_TIMEOUT);

            Http http = new Http();
            HttpResponse res = http.send(req);

            // Parse response
            Integer statusCode = res.getStatusCode();
            String responseBody = res.getBody();

            if (statusCode == 200) {
                // Success
                PdfResponse pdfResponse = (PdfResponse) JSON.deserialize(responseBody, PdfResponse.class);
                result.success = true;
                result.pdfBase64 = pdfResponse.pdf;
                result.contentType = pdfResponse.contentType;
            } else {
                // Error
                try {
                    PdfResponse errorResponse = (PdfResponse) JSON.deserialize(responseBody, PdfResponse.class);
                    result.errorMessage = errorResponse.error;
                    result.errorCode = errorResponse.code;
                } catch (Exception e) {
                    result.errorMessage = 'HTTP ' + statusCode + ': ' + responseBody;
                    result.errorCode = 'HTTP_ERROR';
                }
            }

        } catch (System.CalloutException e) {
            result.errorMessage = 'Callout failed: ' + e.getMessage();
            result.errorCode = 'CALLOUT_ERROR';
        } catch (Exception e) {
            result.errorMessage = 'Unexpected error: ' + e.getMessage();
            result.errorCode = 'UNKNOWN_ERROR';
        }

        return result;
    }

    /**
     * Generate a PDF and save it as a ContentVersion (File) attached to a record
     *
     * @param apiKey The API key for authentication
     * @param templateId The ID of the PDF template to use
     * @param recordId The Salesforce record ID to fetch data from
     * @param fileName The name for the generated PDF file
     * @return The ContentVersion ID if successful, null otherwise
     */
    public static Id generateAndSavePdf(String apiKey, String templateId, Id recordId, String fileName) {
        PdfResult result = generatePdf(apiKey, templateId, recordId);

        if (!result.success) {
            throw new PdfGeneratorException(result.errorCode + ': ' + result.errorMessage);
        }

        // Decode base64 PDF
        Blob pdfBlob = EncodingUtil.base64Decode(result.pdfBase64);

        // Create ContentVersion (File)
        ContentVersion cv = new ContentVersion();
        cv.Title = fileName;
        cv.PathOnClient = fileName.endsWith('.pdf') ? fileName : fileName + '.pdf';
        cv.VersionData = pdfBlob;
        cv.FirstPublishLocationId = recordId;
        insert cv;

        return cv.Id;
    }

    /**
     * Generate a PDF and return it as a Blob
     *
     * @param apiKey The API key for authentication
     * @param templateId The ID of the PDF template to use
     * @param recordId The Salesforce record ID to fetch data from
     * @return Blob containing the PDF data
     */
    public static Blob generatePdfBlob(String apiKey, String templateId, Id recordId) {
        PdfResult result = generatePdf(apiKey, templateId, recordId);

        if (!result.success) {
            throw new PdfGeneratorException(result.errorCode + ': ' + result.errorMessage);
        }

        return EncodingUtil.base64Decode(result.pdfBase64);
    }

    /**
     * Custom exception for PDF generation errors
     */
    public class PdfGeneratorException extends Exception {}
}
