001package ca.cdr.api.util;
002
003/*-
004 * #%L
005 * Smile CDR - CDR
006 * %%
007 * Copyright (C) 2016 - 2026 Smile CDR, Inc.
008 * %%
009 * All rights reserved.
010 * #L%
011 */
012
013import ca.cdr.api.model.enm.TransactionLogBodyTypeEnum;
014import ca.cdr.api.model.enm.TransactionLogOutcomeEnum;
015import ca.cdr.api.model.enm.TransactionLogStepTypeEnum;
016import ca.cdr.api.model.json.TransactionLogStepJson;
017import ca.cdr.api.pub.hl7v2.model.MappingMessage;
018import jakarta.annotation.Nullable;
019
020import java.util.Date;
021import java.util.List;
022import java.util.stream.Collectors;
023
024import static org.apache.commons.lang3.StringUtils.isNotBlank;
025
026public class MessageMappingUtil {
027        private MessageMappingUtil() {}
028
029        /**
030         * Given a set of mapping issues (if any), generate a {@link TransactionLogStepJson}
031         * that can be sent to the transaction log service. Will only return
032         * an object if any issues are actually present, otherwise returns null.
033         *
034         * @return Returns null if no issues detected
035         */
036        @Nullable
037        public static TransactionLogStepJson createTransactionLogStep(List<MappingMessage> theIssues) {
038                if (theIssues.isEmpty()) {
039                        return null;
040                }
041
042                TransactionLogStepJson mapStep = new TransactionLogStepJson();
043                mapStep.setOutcome(hasErrors(theIssues) ? TransactionLogOutcomeEnum.FAIL : TransactionLogOutcomeEnum.SUCCESS);
044                mapStep.setType(TransactionLogStepTypeEnum.PROCESSING);
045                mapStep.setBody(toMarkdown(theIssues));
046                mapStep.setBodyType(TransactionLogBodyTypeEnum.MESSAGE_MARKDOWN);
047                mapStep.setInitialTimestamp(new Date());
048                return mapStep;
049        }
050
051        /**
052         * Returns {@code true} if any of the given mapping issues has a level of
053         * {@link MappingMessage.MessageLevel#ERROR ERROR} or higher.
054         */
055        public static boolean hasErrors(List<MappingMessage> theIssues) {
056                return theIssues.stream().anyMatch(t -> isAtLeastError(t.getLevel()));
057        }
058
059        /**
060         * Returns {@code true} if the given severity level is {@link MappingMessage.MessageLevel#ERROR} or higher.
061         */
062        public static boolean isAtLeastError(MappingMessage.MessageLevel theLevel) {
063                return theLevel.ordinal() >= MappingMessage.MessageLevel.ERROR.ordinal();
064        }
065
066        /**
067         * Formats the given mapping issues as a markdown bullet list.
068         */
069        public static String toMarkdown(List<MappingMessage> theIssues) {
070                StringBuilder messageMarkdown = new StringBuilder();
071                for (MappingMessage nextIssue : theIssues) {
072                        if (!messageMarkdown.isEmpty()) {
073                                messageMarkdown.append("\n");
074                        }
075                        messageMarkdown.append("* ");
076                        messageMarkdown.append("[**").append(nextIssue.getLevel().name()).append("**] ");
077                        if (isNotBlank(nextIssue.getPath())) {
078                                messageMarkdown.append(" `").append(nextIssue.getPath()).append("` - ");
079                        }
080                        messageMarkdown.append(nextIssue.getMessage());
081                }
082                return messageMarkdown.toString();
083        }
084
085        /**
086         * Formats the given mapping issues as a semicolon-delimited string suitable for log output.
087         * Each issue is formatted as {@code [LEVEL] path - message}.
088         */
089        public static String toLogMessage(List<MappingMessage> theIssues) {
090                return theIssues.stream()
091                                .map(i -> "[" + i.getLevel() + "] " + i.getPath() + " - " + i.getMessage())
092                                .collect(Collectors.joining("; "));
093        }
094}