public with sharing class TranscriptGenerator {
	
	@InvocableMethod(label='Generate Transcript' description='Generates the chat transcript for the specified MessagingSession ID.')
	public static void generateChatTranscript(List<FlowInputs> inputs) {
		String messagingSessionId = inputs[0].messagingSessionId;
		performCallout(messagingSessionId);
	}
	
	@future(callout=true)
	public static void performCallout(String messagingSessionId) {
		List<MessagingSession> messageSessionList = [SELECT Id, Conversation.ConversationIdentifier, Transcript__c  FROM MessagingSession WHERE Id = :messagingSessionId];
		if(!messageSessionList.isEmpty() && messageSessionList[0].Conversation.ConversationIdentifier != null) {
			String endpoint = URL.getOrgDomainURL().toExternalForm() + '/services/data/v61.0/connect/conversation/' + messageSessionList[0].Conversation.ConversationIdentifier + '/entries?queryDirection=FromStart&recordLimit=1000';
			// Send HTTP request
			Http h = new Http();
			HttpRequest req = new HttpRequest();
			req.setEndpoint(endpoint);
			req.setMethod('GET');
			req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
			HttpResponse res = h.send(req);
			String payload = res.getBody();
			System.debug('STATUS CODE   : ' + res.getStatusCode());
			System.debug('STATUS        : ' + res.getStatus());
			System.debug('PAYLOAD       : ' + payload);
			if (res.getStatusCode() == 200) {
				ConversationWrapper conversation = ConversationWrapper.parse(payload);
				ConversationEntriesCompare convCompare = new ConversationEntriesCompare();
				conversation.conversationEntries.sort(convCompare);
				List<String> formattedConversationEntries = new List<String>();
				for(ConversationEntries convEntry : conversation.conversationEntries) {
					formattedConversationEntries.add(
						'[' + Datetime.newInstance(convEntry.serverReceivedTimestamp) + '] ' +
						'[' + convEntry.sender.role + ']\t: ' +
						convEntry.messageText
						);
				}
				String formattedConversation = String.join(formattedConversationEntries, '\n');
				System.debug('\n' + formattedConversation);
				
				// Formatted conversation from formattedConversation can be stored in any field and then mapped in the field mapping.
				messageSessionList[0].Transcript__c = formattedConversation;
				update messageSessionList;
			}
		}
	}
	
	public class FlowInputs {
		@InvocableVariable(label='MessagingSession Id' description='Record id of the MessagingSession' required=true)
		public String messagingSessionId;
	}
	
	// Wrapper classes
	public class Sender {
		public String appType;
		public String role;
		public String subject;
	}
	public class ConversationEntries {
		public Integer clientDuration;
		public Long clientTimestamp;
		public String identifier;
		public String messageText;
		public List<String> relatedRecords;
		public Sender sender;
		public Long serverReceivedTimestamp;
	}
	public class ConversationWrapper {
		public List<ConversationEntries> conversationEntries;
	}
	// Method to deserialize the payload as ConversationWrapper type
	public static ConversationWrapper parse(String json) {
		return (ConversationWrapper) System.JSON.deserialize(json, ConversationWrapper.class);
	}
	// Comparator class to sort the ConversationEntries
	public class ConversationEntriesCompare implements Comparator<ConversationEntries> {
		// Sort the ConversationEntries based on serverReceivedTimestamp
		public Integer compare(ConversationEntries e1, ConversationEntries e2) {
			Integer result;
			if(e1?.serverReceivedTimestamp == null && e2?.serverReceivedTimestamp == null) {
				result = 0;
			} else if(e1?.serverReceivedTimestamp == null) {
				result = -1;
			} else if(e2?.serverReceivedTimestamp == null) {
				result = 1;
			} else if (e1.serverReceivedTimestamp < e2.serverReceivedTimestamp) {
				result = -1;
			} else if (e1.serverReceivedTimestamp > e2.serverReceivedTimestamp) {
				result = 1;
			} else {
				result = 0;
			}
			return result;
		}
	}
	
}