public with sharing class CLMAdminService {
    public class CaseDeficiencyItem {
        @AuraEnabled public Id recordId;
        @AuraEnabled public Decimal deficiencyNumber;
        @AuraEnabled public String description;
        @AuraEnabled public String resolution;
        @AuraEnabled public String reference;
    }

    public class CaseContext {
        @AuraEnabled public Id caseId;
        @AuraEnabled public String caseNumber;
        @AuraEnabled public String propertyAddress;
        @AuraEnabled public String lastDocGenStatus;
        @AuraEnabled public String lastDocGenMessage;
        @AuraEnabled public String lastClmAccountCode;
        @AuraEnabled public String lastDocGenTaskId;
        @AuraEnabled public String lastDocGenTaskUrl;
        @AuraEnabled public String generatedDocumentUrl;
        @AuraEnabled public String generatedDocumentId;
        @AuraEnabled public String attachedFileContentDocumentId;
        @AuraEnabled public String attachedFileUrl;
        @AuraEnabled public Datetime lastDocGenRequestedAt;
        @AuraEnabled public Datetime lastDocGenCompletedAt;
        @AuraEnabled public List<CaseDeficiencyItem> deficiencies;
    }

    public class FileAttachmentResult {
        @AuraEnabled public Boolean success;
        @AuraEnabled public String message;
        @AuraEnabled public String contentDocumentId;
        @AuraEnabled public String fileUrl;
        @AuraEnabled public String fileTitle;
    }

    public class AccountSettings {
        @AuraEnabled public String accountCode;
        @AuraEnabled public String accountDisplayName;
        @AuraEnabled public String environment;
        @AuraEnabled public String clmAccountId;
        @AuraEnabled public String clmApiNamedCredential;
        @AuraEnabled public String clmDownloadNamedCredential;
        @AuraEnabled public String eSignatureRestNamedCredential;
        @AuraEnabled public String templateRootFolderHref;
        @AuraEnabled public String destinationRootFolderHref;
        @AuraEnabled public String defaultTemplateDocumentHref;
        @AuraEnabled public String defaultDocumentNamePrefix;
        @AuraEnabled public Boolean active;
    }

    public class LetterSettings {
        @AuraEnabled public String accountCode;
        @AuraEnabled public String letterCode;
        @AuraEnabled public String letterDisplayName;
        @AuraEnabled public String description;
        @AuraEnabled public Boolean isDefault;
        @AuraEnabled public Decimal sortOrder;
        @AuraEnabled public String templateRootFolderHref;
        @AuraEnabled public String destinationRootFolderHref;
        @AuraEnabled public String defaultTemplateDocumentHref;
        @AuraEnabled public String defaultDocumentNamePrefix;
        @AuraEnabled public Boolean active;
    }

    public class ResourceItem {
        @AuraEnabled public String name;
        @AuraEnabled public String href;
        @AuraEnabled public String type;
        @AuraEnabled public String parentHref;
        @AuraEnabled public String rawJson;
    }

    public class FolderContents {
        @AuraEnabled public ResourceItem folder;
        @AuraEnabled public List<ResourceItem> folders;
        @AuraEnabled public List<ResourceItem> documents;
    }

    public class DocGenPreview {
        @AuraEnabled public String accountCode;
        @AuraEnabled public String accountDisplayName;
        @AuraEnabled public String letterCode;
        @AuraEnabled public String letterDisplayName;
        @AuraEnabled public String mergeTaskEndpointUrl;
        @AuraEnabled public String templateDocHref;
        @AuraEnabled public String destinationFolderHref;
        @AuraEnabled public String destinationDocName;
        @AuraEnabled public String payloadJson;
        @AuraEnabled public String dataXml;
        @AuraEnabled public String requestBodyJson;
    }

    @AuraEnabled(cacheable=true)
    public static List<AccountSettings> listAccountSettings() {
        List<AccountSettings> settings = new List<AccountSettings>();
        for (CLM_Account_Setting__mdt row : [
            SELECT DeveloperName,
                   Account_Code__c,
                   Account_Display_Name__c,
                   Environment_Code__c,
                   CLM_Account_Id__c,
                   CLM_Api_Named_Credential__c,
                   CLM_Download_Named_Credential__c,
                   ESignature_Rest_Named_Credential__c,
                   Template_Root_Folder_Href__c,
                   Destination_Root_Folder_Href__c,
                   Default_Template_Document_Href__c,
                   Default_Destination_Document_Name_Prefix__c,
                   Active__c
              FROM CLM_Account_Setting__mdt
             WHERE Active__c = true
             ORDER BY Account_Display_Name__c ASC, DeveloperName ASC
        ]) {
            settings.add(toAccountSettings(row));
        }
        return settings;
    }

    @AuraEnabled(cacheable=true)
    public static AccountSettings getAccountSettings(String accountCode) {
        CLM_Account_Setting__mdt row = resolveAccountSetting(accountCode);
        return row == null ? null : toAccountSettings(row);
    }

    @AuraEnabled(cacheable=true)
    public static List<LetterSettings> listLetterSettings(String accountCode) {
        AccountSettings account = getAccountSettings(accountCode);
        List<LetterSettings> letters = new List<LetterSettings>();
        if (account == null) {
            return letters;
        }

        for (CLM_Letter_Definition__mdt row : [
            SELECT DeveloperName,
                   Account_Code__c,
                   Letter_Code__c,
                   Letter_Display_Name__c,
                   Description__c,
                   Active__c,
                   Is_Default__c,
                   Sort_Order__c,
                   Template_Root_Folder_Href__c,
                   Destination_Root_Folder_Href__c,
                   Default_Template_Document_Href__c,
                   Default_Destination_Document_Name_Prefix__c
              FROM CLM_Letter_Definition__mdt
             WHERE Active__c = true
               AND Account_Code__c = :account.accountCode
             ORDER BY Is_Default__c DESC, Sort_Order__c ASC, Letter_Display_Name__c ASC, DeveloperName ASC
        ]) {
            letters.add(toLetterSettings(row, account));
        }

        if (letters.isEmpty()) {
            letters.add(buildFallbackLetterSettings(account));
        }
        return letters;
    }

    @AuraEnabled(cacheable=true)
    public static LetterSettings getLetterSettings(String accountCode, String letterCode) {
        AccountSettings account = getAccountSettings(accountCode);
        if (account == null) {
            return null;
        }

        String normalizedLetterCode = String.isBlank(letterCode) ? null : letterCode.trim();
        if (String.isNotBlank(normalizedLetterCode)) {
            List<CLM_Letter_Definition__mdt> rows = [
                SELECT DeveloperName,
                       Account_Code__c,
                       Letter_Code__c,
                       Letter_Display_Name__c,
                       Description__c,
                       Active__c,
                       Is_Default__c,
                       Sort_Order__c,
                       Template_Root_Folder_Href__c,
                       Destination_Root_Folder_Href__c,
                       Default_Template_Document_Href__c,
                       Default_Destination_Document_Name_Prefix__c
                  FROM CLM_Letter_Definition__mdt
                 WHERE Active__c = true
                   AND Account_Code__c = :account.accountCode
                   AND Letter_Code__c = :normalizedLetterCode
                 LIMIT 1
            ];
            if (!rows.isEmpty()) {
                return toLetterSettings(rows[0], account);
            }
        }

        List<LetterSettings> letters = listLetterSettings(account.accountCode);
        for (LetterSettings letter : letters) {
            if (letter.isDefault) {
                return letter;
            }
        }
        return letters.isEmpty() ? buildFallbackLetterSettings(account) : letters[0];
    }

    @AuraEnabled(cacheable=false)
    public static CLMDocGenCallout.CLMDocGenResponse generateDocument(
        Id appraiserCaseId,
        String templateDocHref,
        String destinationFolderHref,
        String destinationDocName,
        String accountCode
    ) {
        CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
        CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument(
            (String) appraiserCaseId,
            templateDocHref,
            destinationFolderHref,
            destinationDocName,
            account.Environment_Code__c,
            account.CLM_Account_Id__c,
            account.CLM_Api_Named_Credential__c
        );
        persistDocGenResult(appraiserCaseId, templateDocHref, destinationFolderHref, response, false, accountCode);
        return response;
    }

    @AuraEnabled(cacheable=false)
    public static CLMDocGenCallout.CLMDocGenResponse getTaskStatus(Id appraiserCaseId, String taskId, String accountCode) {
        CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
        CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.getTaskStatus(
            taskId,
            account.Environment_Code__c,
            account.CLM_Account_Id__c,
            account.CLM_Api_Named_Credential__c
        );
        persistDocGenResult(appraiserCaseId, null, null, response, true, accountCode);
        return response;
    }

    @AuraEnabled(cacheable=false)
    public static String probeResource(String resourceOrHref, String accountCode) {
        CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
        return performGet(resourceOrHref, account).getBody();
    }

    @AuraEnabled(cacheable=false)
    public static DocGenPreview getDocGenPreview(Id appraiserCaseId, String accountCode, String letterCode) {
        if (appraiserCaseId == null) {
            throw new AuraHandledException('appraiserCaseId is required');
        }

        AccountSettings account = getAccountSettings(accountCode);
        if (account == null) {
            throw new AuraHandledException('No active CLM account setting was found for ' + accountCode + '.');
        }

        LetterSettings letter = getLetterSettings(account.accountCode, letterCode);
        List<Appraiser_Case__c> previewRows = [
            SELECT Id, Name
              FROM Appraiser_Case__c
             WHERE Id = :appraiserCaseId
             LIMIT 1
        ];
        if (previewRows.isEmpty()) {
            throw new AuraHandledException('Appraiser Case not found: ' + appraiserCaseId);
        }
        Appraiser_Case__c appraiserCase = previewRows[0];

        String prefix = letter != null && String.isNotBlank(letter.defaultDocumentNamePrefix)
            ? letter.defaultDocumentNamePrefix
            : account.defaultDocumentNamePrefix;

        DocGenPreview preview = new DocGenPreview();
        preview.accountCode = account.accountCode;
        preview.accountDisplayName = account.accountDisplayName;
        preview.letterCode = letter != null ? letter.letterCode : 'APPRAISER_REVIEW';
        preview.letterDisplayName = letter != null ? letter.letterDisplayName : 'Appraiser Review Letter';
        preview.templateDocHref = letter != null ? letter.defaultTemplateDocumentHref : account.defaultTemplateDocumentHref;
        preview.destinationFolderHref = letter != null ? letter.destinationRootFolderHref : account.destinationRootFolderHref;
        preview.destinationDocName = buildDefaultDocumentName(prefix, appraiserCase.Name);
        preview.mergeTaskEndpointUrl = CLMDocGenCallout.buildDocumentXmlMergeTasksUrl(
            preview.templateDocHref,
            preview.destinationFolderHref,
            account.environment,
            account.clmAccountId
        );
        preview.payloadJson = JSON.serializePretty(AppraiserCasePayloadBuilder.buildPayload((String) appraiserCaseId));
        preview.dataXml = CLMDocGenCallout.prettyPrintXml(CLMDocGenCallout.buildDataXmlForCase((String) appraiserCaseId));
        preview.requestBodyJson = CLMDocGenCallout.buildRequestBodyJson(
            (String) appraiserCaseId,
            preview.templateDocHref,
            preview.destinationFolderHref,
            preview.destinationDocName
        );
        return preview;
    }

    @AuraEnabled(cacheable=false)
    public static CaseContext getCaseContext(Id appraiserCaseId) {
        List<Appraiser_Case__c> contextRows = [
            SELECT Id,
                   Name,
                   Property_Street__c,
                   Property_City__c,
                   Property_State_Province__c,
                   Property_Postal_Code__c,
                   Property_Country__c,
                   Last_DocGen_Status__c,
                   Last_DocGen_Message__c,
                   Last_CLM_Account_Code__c,
                   Last_DocGen_Task_Id__c,
                   Last_DocGen_Task_Url__c,
                   Generated_Document_Url__c,
                   Generated_Document_Id__c,
                   Attached_File_Content_Document_Id__c,
                   Attached_File_Url__c,
                   Last_DocGen_Requested_At__c,
                   Last_DocGen_Completed_At__c,
                   (SELECT Id,
                           Deficiency_Number__c,
                           Description__c,
                           Resolution__c,
                           Reference__c
                      FROM Deficiencies__r
                      ORDER BY Deficiency_Number__c ASC, CreatedDate ASC)
              FROM Appraiser_Case__c
             WHERE Id = :appraiserCaseId
             LIMIT 1
        ];
        if (contextRows.isEmpty()) {
            throw new AuraHandledException('Appraiser Case not found: ' + appraiserCaseId);
        }
        Appraiser_Case__c appraiserCase = contextRows[0];

        CaseContext context = new CaseContext();
        context.caseId = appraiserCase.Id;
        context.caseNumber = appraiserCase.Name;
        context.propertyAddress = formatAddress(appraiserCase);
        context.lastDocGenStatus = appraiserCase.Last_DocGen_Status__c;
        context.lastDocGenMessage = appraiserCase.Last_DocGen_Message__c;
        context.lastClmAccountCode = appraiserCase.Last_CLM_Account_Code__c;
        context.lastDocGenTaskId = appraiserCase.Last_DocGen_Task_Id__c;
        context.lastDocGenTaskUrl = appraiserCase.Last_DocGen_Task_Url__c;
        context.generatedDocumentUrl = appraiserCase.Generated_Document_Url__c;
        context.generatedDocumentId = appraiserCase.Generated_Document_Id__c;
        context.attachedFileContentDocumentId = appraiserCase.Attached_File_Content_Document_Id__c;
        context.attachedFileUrl = appraiserCase.Attached_File_Url__c;
        context.lastDocGenRequestedAt = appraiserCase.Last_DocGen_Requested_At__c;
        context.lastDocGenCompletedAt = appraiserCase.Last_DocGen_Completed_At__c;
        context.deficiencies = new List<CaseDeficiencyItem>();

        if (appraiserCase.Deficiencies__r != null) {
            for (Appraiser_Case_Deficiency__c deficiency : appraiserCase.Deficiencies__r) {
                CaseDeficiencyItem item = new CaseDeficiencyItem();
                item.recordId = deficiency.Id;
                item.deficiencyNumber = deficiency.Deficiency_Number__c;
                item.description = deficiency.Description__c;
                item.resolution = deficiency.Resolution__c;
                item.reference = deficiency.Reference__c;
                context.deficiencies.add(item);
            }
        }

        return context;
    }

    @AuraEnabled(cacheable=false)
    public static FileAttachmentResult attachGeneratedDocumentToCase(Id appraiserCaseId, String accountCode) {
        if (appraiserCaseId == null) {
            throw new AuraHandledException('appraiserCaseId is required');
        }
        CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);

        Appraiser_Case__c appraiserCase = [
            SELECT Id,
                   Name,
                   Generated_Document_Url__c,
                   Generated_Document_Id__c
              FROM Appraiser_Case__c
             WHERE Id = :appraiserCaseId
             LIMIT 1
        ];

        if (String.isBlank(appraiserCase.Generated_Document_Url__c)) {
            throw new AuraHandledException('No generated document is available to attach yet.');
        }

        CLMDocGenCallout.DownloadedDocument downloaded = CLMDocGenCallout.downloadDocument(
            appraiserCase.Generated_Document_Url__c,
            account.Environment_Code__c,
            account.CLM_Account_Id__c,
            account.CLM_Download_Named_Credential__c
        );
        String fileName = String.isNotBlank(downloaded.fileName)
            ? downloaded.fileName
            : 'Generated_' + appraiserCase.Name + '.docx';
        String title = fileName.contains('.')
            ? fileName.substringBeforeLast('.')
            : fileName;

        ContentVersion version = new ContentVersion(
            Title = title,
            PathOnClient = '/' + fileName,
            VersionData = downloaded.body
        );
        insert version;

        version = [
            SELECT Id, ContentDocumentId
              FROM ContentVersion
             WHERE Id = :version.Id
             LIMIT 1
        ];

        insert new ContentDocumentLink(
            ContentDocumentId = version.ContentDocumentId,
            LinkedEntityId = appraiserCase.Id,
            ShareType = 'V',
            Visibility = 'AllUsers'
        );

        String fileUrl = '/lightning/r/ContentDocument/' + version.ContentDocumentId + '/view';
        update new Appraiser_Case__c(
            Id = appraiserCase.Id,
            Last_CLM_Account_Code__c = accountCode,
            Attached_File_Content_Document_Id__c = version.ContentDocumentId,
            Attached_File_Url__c = fileUrl
        );

        FileAttachmentResult result = new FileAttachmentResult();
        result.success = true;
        result.message = 'Generated document attached to the case.';
        result.contentDocumentId = version.ContentDocumentId;
        result.fileUrl = fileUrl;
        result.fileTitle = title;
        return result;
    }

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

    @AuraEnabled(cacheable=false)
    public static FolderContents getFolderContents(String folderHref, String accountCode) {
        if (String.isBlank(folderHref)) {
            throw new IllegalArgumentException('folderHref is required');
        }
        CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);

        FolderContents contents = new FolderContents();
        contents.folder = parseSingleResource(performGet(folderHref, account).getBody(), 'Folder');
        contents.folders = parseResourceList(performGet(folderHref + '/folders', account).getBody(), 'Folder', folderHref);
        contents.documents = parseResourceList(performGet(folderHref + '/documents', account).getBody(), 'Document', folderHref);
        return contents;
    }

    private static HttpResponse performGet(String resourceOrHref, CLM_Account_Setting__mdt account) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(CLMDocGenCallout.buildEndpointForResource(
            resourceOrHref,
            account.CLM_Account_Id__c,
            account.CLM_Api_Named_Credential__c
        ));
        req.setMethod('GET');
        req.setTimeout(CLMDocGenCallout.HTTP_TIMEOUT);

        HttpResponse res = new Http().send(req);
        Integer statusCode = res.getStatusCode();
        if (statusCode < 200 || statusCode >= 300) {
            throw new AuraHandledException('CLM API Error (HTTP ' + statusCode + '): ' + res.getBody());
        }

        return res;
    }

    @TestVisible
    private static ResourceItem parseSingleResource(String body, String defaultType) {
        Object root = JSON.deserializeUntyped(body);
        if (!(root instanceof Map<String, Object>)) {
            return null;
        }
        return parseResource((Map<String, Object>) root, defaultType, null);
    }

    @TestVisible
    private static List<ResourceItem> parseResourceList(String body, String defaultType, String parentHref) {
        Object root = JSON.deserializeUntyped(body);
        List<Object> records = unwrapList(root);
        List<ResourceItem> items = new List<ResourceItem>();

        for (Object record : records) {
            if (record instanceof Map<String, Object>) {
                items.add(parseResource((Map<String, Object>) record, defaultType, parentHref));
            }
        }

        return items;
    }

    private static List<Object> unwrapList(Object root) {
        if (root instanceof List<Object>) {
            return (List<Object>) root;
        }

        if (root instanceof Map<String, Object>) {
            Map<String, Object> payload = (Map<String, Object>) root;
            for (String key : new List<String>{ 'Results', 'Items', 'Documents', 'Folders' }) {
                Object value = payload.get(key);
                if (value instanceof List<Object>) {
                    return (List<Object>) value;
                }
            }

            if (payload.size() == 1) {
                for (Object value : payload.values()) {
                    if (value instanceof List<Object>) {
                        return (List<Object>) value;
                    }
                }
            }
        }

        return new List<Object>();
    }

    private static ResourceItem parseResource(Map<String, Object> source, String defaultType, String parentHref) {
        ResourceItem item = new ResourceItem();
        item.name = firstString(source, new List<String>{ 'Name', 'DisplayName', 'Title', 'Label' });
        item.href = firstString(source, new List<String>{ 'Href', 'Uri', 'Location' });
        item.type = firstString(source, new List<String>{ 'Type', 'ObjectType', 'ItemType' });
        item.parentHref = extractParentHref(source, parentHref);
        item.rawJson = JSON.serialize(source);

        if (String.isBlank(item.type)) {
            item.type = defaultType;
        }

        if (String.isBlank(item.name) && String.isNotBlank(item.href)) {
            item.name = item.href.substringAfterLast('/');
        }

        return item;
    }

    private static String extractParentHref(Map<String, Object> source, String fallbackValue) {
        Object parentValue = source.get('Parent');
        if (parentValue instanceof Map<String, Object>) {
            String href = firstString((Map<String, Object>) parentValue, new List<String>{ 'Href', 'Uri', 'Location' });
            if (String.isNotBlank(href)) {
                return href;
            }
        }
        return fallbackValue;
    }

    private static String firstString(Map<String, Object> source, List<String> keys) {
        for (String key : keys) {
            Object value = source.get(key);
            if (value != null) {
                String textValue = String.valueOf(value);
                if (String.isNotBlank(textValue)) {
                    return textValue;
                }
            }
        }
        return null;
    }

    private static void persistDocGenResult(
        Id appraiserCaseId,
        String templateDocHref,
        String destinationFolderHref,
        CLMDocGenCallout.CLMDocGenResponse response,
        Boolean isStatusRefresh,
        String accountCode
    ) {
        if (appraiserCaseId == null || response == null) {
            return;
        }

        Appraiser_Case__c updateCase = new Appraiser_Case__c(Id = appraiserCaseId);
        updateCase.Last_CLM_Account_Code__c = accountCode;
        updateCase.Last_DocGen_Status__c = String.isNotBlank(response.taskStatus) ? response.taskStatus : (response.success ? 'Submitted' : 'Failed');
        updateCase.Last_DocGen_Message__c = response.message;
        updateCase.Last_DocGen_Task_Id__c = response.documentId;
        updateCase.Last_DocGen_Task_Url__c = response.documentUrl;

        if (!isStatusRefresh) {
            updateCase.Last_DocGen_Requested_At__c = System.now();
            updateCase.Last_Template_Document_Href__c = templateDocHref;
            updateCase.Last_Destination_Folder_Href__c = destinationFolderHref;
        }

        if (String.isNotBlank(response.generatedDocumentUrl)) {
            updateCase.Generated_Document_Url__c = response.generatedDocumentUrl;
            updateCase.Generated_Document_Id__c = response.generatedDocumentId;
        }

        if (response.success && String.valueOf(response.taskStatus).toLowerCase() == 'completed') {
            updateCase.Last_DocGen_Completed_At__c = System.now();
        }

        update updateCase;
    }

    private static CLM_Account_Setting__mdt requireAccountSetting(String accountCode) {
        CLM_Account_Setting__mdt row = resolveAccountSetting(accountCode);
        if (row == null) {
            throw new AuraHandledException('No active CLM account setting was found for ' + accountCode + '.');
        }
        return row;
    }

    private static CLM_Account_Setting__mdt resolveAccountSetting(String accountCode) {
        String normalizedCode = String.isBlank(accountCode) ? null : accountCode.trim();
        List<CLM_Account_Setting__mdt> rows;
        if (String.isNotBlank(normalizedCode)) {
            rows = [
                SELECT DeveloperName,
                       Account_Code__c,
                       Account_Display_Name__c,
                       Environment_Code__c,
                       CLM_Account_Id__c,
                       CLM_Api_Named_Credential__c,
                       CLM_Download_Named_Credential__c,
                       ESignature_Rest_Named_Credential__c,
                       Template_Root_Folder_Href__c,
                       Destination_Root_Folder_Href__c,
                       Default_Template_Document_Href__c,
                       Default_Destination_Document_Name_Prefix__c,
                       Active__c
                  FROM CLM_Account_Setting__mdt
                 WHERE Active__c = true
                   AND DeveloperName = :normalizedCode
                 LIMIT 1
            ];
            if (rows.isEmpty()) {
                rows = [
                    SELECT DeveloperName,
                           Account_Code__c,
                           Account_Display_Name__c,
                           Environment_Code__c,
                           CLM_Account_Id__c,
                           CLM_Api_Named_Credential__c,
                           CLM_Download_Named_Credential__c,
                           ESignature_Rest_Named_Credential__c,
                           Template_Root_Folder_Href__c,
                           Destination_Root_Folder_Href__c,
                           Default_Template_Document_Href__c,
                           Default_Destination_Document_Name_Prefix__c,
                           Active__c
                      FROM CLM_Account_Setting__mdt
                     WHERE Active__c = true
                       AND Account_Code__c = :normalizedCode
                     LIMIT 1
                ];
            }
        } else {
            rows = [
                SELECT DeveloperName,
                       Account_Code__c,
                       Account_Display_Name__c,
                       Environment_Code__c,
                       CLM_Account_Id__c,
                       CLM_Api_Named_Credential__c,
                       CLM_Download_Named_Credential__c,
                       ESignature_Rest_Named_Credential__c,
                       Template_Root_Folder_Href__c,
                       Destination_Root_Folder_Href__c,
                       Default_Template_Document_Href__c,
                       Default_Destination_Document_Name_Prefix__c,
                       Active__c
                  FROM CLM_Account_Setting__mdt
                 WHERE Active__c = true
                 ORDER BY Account_Display_Name__c ASC, DeveloperName ASC
                 LIMIT 1
            ];
        }
        return rows.isEmpty() ? null : rows[0];
    }

    private static AccountSettings toAccountSettings(CLM_Account_Setting__mdt row) {
        AccountSettings settings = new AccountSettings();
        settings.accountCode = String.isNotBlank(row.Account_Code__c) ? row.Account_Code__c : row.DeveloperName;
        settings.accountDisplayName = String.isNotBlank(row.Account_Display_Name__c) ? row.Account_Display_Name__c : row.DeveloperName;
        settings.environment = row.Environment_Code__c;
        settings.clmAccountId = row.CLM_Account_Id__c;
        settings.clmApiNamedCredential = row.CLM_Api_Named_Credential__c;
        settings.clmDownloadNamedCredential = row.CLM_Download_Named_Credential__c;
        settings.eSignatureRestNamedCredential = row.ESignature_Rest_Named_Credential__c;
        settings.templateRootFolderHref = row.Template_Root_Folder_Href__c;
        settings.destinationRootFolderHref = row.Destination_Root_Folder_Href__c;
        settings.defaultTemplateDocumentHref = row.Default_Template_Document_Href__c;
        settings.defaultDocumentNamePrefix = row.Default_Destination_Document_Name_Prefix__c;
        settings.active = row.Active__c;
        return settings;
    }

    private static LetterSettings toLetterSettings(CLM_Letter_Definition__mdt row, AccountSettings account) {
        LetterSettings settings = new LetterSettings();
        settings.accountCode = String.isNotBlank(row.Account_Code__c) ? row.Account_Code__c : account.accountCode;
        settings.letterCode = String.isNotBlank(row.Letter_Code__c) ? row.Letter_Code__c : 'APPRAISER_REVIEW';
        settings.letterDisplayName = String.isNotBlank(row.Letter_Display_Name__c) ? row.Letter_Display_Name__c : row.DeveloperName;
        settings.description = row.Description__c;
        settings.isDefault = row.Is_Default__c;
        settings.sortOrder = row.Sort_Order__c;
        settings.templateRootFolderHref = firstNonBlankValue(row.Template_Root_Folder_Href__c, account.templateRootFolderHref);
        settings.destinationRootFolderHref = firstNonBlankValue(row.Destination_Root_Folder_Href__c, account.destinationRootFolderHref);
        settings.defaultTemplateDocumentHref = firstNonBlankValue(row.Default_Template_Document_Href__c, account.defaultTemplateDocumentHref);
        settings.defaultDocumentNamePrefix = firstNonBlankValue(row.Default_Destination_Document_Name_Prefix__c, account.defaultDocumentNamePrefix);
        settings.active = row.Active__c;
        return settings;
    }

    private static LetterSettings buildFallbackLetterSettings(AccountSettings account) {
        LetterSettings settings = new LetterSettings();
        settings.accountCode = account.accountCode;
        settings.letterCode = 'APPRAISER_REVIEW';
        settings.letterDisplayName = 'Appraiser Review Letter';
        settings.description = 'Fallback current appraiser letter flow.';
        settings.isDefault = true;
        settings.sortOrder = 10;
        settings.templateRootFolderHref = account.templateRootFolderHref;
        settings.destinationRootFolderHref = account.destinationRootFolderHref;
        settings.defaultTemplateDocumentHref = account.defaultTemplateDocumentHref;
        settings.defaultDocumentNamePrefix = account.defaultDocumentNamePrefix;
        settings.active = true;
        return settings;
    }

    private static String firstNonBlankValue(String preferredValue, String fallbackValue) {
        return String.isNotBlank(preferredValue) ? preferredValue : fallbackValue;
    }

    private static String buildDefaultDocumentName(String prefix, String caseNumber) {
        String normalizedPrefix = String.isNotBlank(prefix) ? prefix : 'Review';
        return String.isNotBlank(caseNumber)
            ? normalizedPrefix + '_' + caseNumber + '.docx'
            : normalizedPrefix + '.docx';
    }
}
