import { envMode, LiveAgentAuthExpiredError } from "../liveagent-types";
import { ChatEventBus } from "../chateventbus";
import { Logger, LogLevel } from "../../logger";
import { getEndpoint } from "../../utils";
const logger = new Logger("SalesforceLiveAgentProvider", {
    logLevel: LogLevel.Info, // Set to Debug for detailed logs",
    remoteLoggingUrl: "",
});
/**
 * Refactor the salesforce implementation with the Messaging for In-App and Web REST API instead of chatter
 */
export class SalesforceLiveAgentProvider {
    constructor() {
        this.configSettings = null;
        this.sessionContext = null;
        this.endpointSSE = "";
        this.checkAgentAvailability = async (conversationId) => {
            var _a, _b, _c;
            this.availabilityAbort = new AbortController();
            const { signal } = this.availabilityAbort;
            // MIAW routing is async — poll until a RoutingResult entry appears or we time out.
            const POLL_INTERVAL_MS = 1500;
            const MAX_WAIT_MS = 20000;
            const startTime = Date.now();
            while (Date.now() - startTime < MAX_WAIT_MS) {
                if (signal.aborted)
                    return false;
                const availabilityRes = await fetch(`${(_a = this.configSettings) === null || _a === void 0 ? void 0 : _a.instanceUrl}/iamessage/api/v2/conversation/${conversationId}/entries`, {
                    method: "GET",
                    signal,
                    headers: {
                        "Content-Type": "application/json",
                        "Authorization": `Bearer ${(_b = this.sessionContext) === null || _b === void 0 ? void 0 : _b.accessToken}`,
                    },
                });
                if (!availabilityRes.ok) {
                    logger.warn(`Agent availability check failed: ${availabilityRes.status} ${availabilityRes.statusText}`);
                    ChatEventBus.emit("AGENT_UNAVAILABLE", { reason: "request_error" });
                    return false;
                }
                const availabilityData = await availabilityRes.json();
                logger.debug("Agent availability check result:", availabilityData);
                const entries = (_c = availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.conversationEntries) !== null && _c !== void 0 ? _c : [];
                const routingEntry = entries.find((e) => e.entryType === "RoutingResult");
                if (routingEntry) {
                    // entryPayload may arrive as a JSON string — parse it if needed
                    let entryPayload = routingEntry.entryPayload;
                    if (typeof entryPayload === "string") {
                        try {
                            entryPayload = JSON.parse(entryPayload);
                        }
                        catch (_d) {
                            logger.warn("Failed to parse RoutingResult entryPayload");
                        }
                    }
                    const failureReason = entryPayload === null || entryPayload === void 0 ? void 0 : entryPayload.failureReason;
                    if (failureReason) {
                        logger.warn("Routing failed with reason:", failureReason);
                        ChatEventBus.emit("AGENT_UNAVAILABLE", { reason: failureReason });
                        return false;
                    }
                    logger.debug("Agent routed successfully");
                    return true;
                }
                // conversationEntries is empty — routing hasn't completed yet, retry
                logger.debug(`No RoutingResult yet (entries: ${entries.length}), retrying in ${POLL_INTERVAL_MS}ms…`);
                // await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS))
                await new Promise((resolve, reject) => {
                    const t = setTimeout(resolve, POLL_INTERVAL_MS);
                    signal.addEventListener("abort", () => { clearTimeout(t); reject(); }, { once: true });
                }).catch(() => null);
            }
            // Timed out — no routing result arrived within the window
            logger.warn("Timed out waiting for MIAW routing result");
            ChatEventBus.emit("AGENT_UNAVAILABLE", { reason: "timeout" });
            return false;
        };
        this.configSettings = null;
        this.sessionContext = null;
        this.endpointSSE = getEndpoint(envMode);
    }
    /**
     * Authenticates with Salesforce MIAW and retrieves an access token.
     * This method should be called before starting a chat session.
     * @throws {Error} If authentication fails.
     * @returns {Promise<void>}
     * @memberof SalesforceLiveAgentProvider
     * @description This method sends a POST request to the Salesforce MIAW authorization endpoint to obtain an access token.
     * The access token is stored in the session context for subsequent API calls.
     */
    async authenticate() {
        var _a, _b, _c;
        const response = await fetch(`${(_a = this.configSettings) === null || _a === void 0 ? void 0 : _a.instanceUrl}/iamessage/api/v2/authorization/unauthenticated/access-token`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
                orgId: (_b = this.configSettings) === null || _b === void 0 ? void 0 : _b.orgId,
                esDeveloperName: (_c = this.configSettings) === null || _c === void 0 ? void 0 : _c.messagingChannelId,
                capabilitiesVersion: "1",
                platform: "Web",
                context: {
                    appName: "DemoMessagingClient",
                    clientVersion: "1.0.0",
                },
            }),
        });
        if (!response.ok) {
            throw new Error(`Failed to authenticate with Salesforce MIAW: [error]: ${response.status} ${response.statusText}`);
        }
        const data = await response.json();
        if (!this.sessionContext)
            this.sessionContext = {};
        this.sessionContext.accessToken = data.accessToken;
        this.sessionContext.sessionId = data.lastEventId;
    }
    /**
     * Starts a new chat session with Salesforce Live Agent.
     * This method should be called after authentication to initiate a chat session.
     * @throws {Error} If starting the chat session fails.
     * @returns {Promise<void>}
     * @memberof SalesforceLiveAgentProvider
     * @description This method creates a new conversation in Salesforce and sets up the session context.
     * It emits a "liveAgentReady" event when the session is successfully started.
     */
    async startSession() {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
        const prechatRoutingAttributes = {};
        if ((_b = (_a = this.sessionContext) === null || _a === void 0 ? void 0 : _a.extraPrechatFormDetails) === null || _b === void 0 ? void 0 : _b.length) {
            for (const detail of this.sessionContext.extraPrechatFormDetails) {
                if ((detail === null || detail === void 0 ? void 0 : detail.label) && typeof detail.value === "string" && detail.value.trim() !== "") {
                    prechatRoutingAttributes[detail.label] = detail.value;
                }
            }
        }
        const conversationId = crypto.randomUUID().toLowerCase();
        const conversationResponse = await fetch(`${(_c = this.configSettings) === null || _c === void 0 ? void 0 : _c.instanceUrl}/iamessage/api/v2/conversation`, {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${(_d = this.sessionContext) === null || _d === void 0 ? void 0 : _d.accessToken}`,
            },
            body: JSON.stringify({
                conversationId: conversationId,
                esDeveloperName: (_e = this.configSettings) === null || _e === void 0 ? void 0 : _e.messagingChannelId,
                routingAttributes: Object.assign({ recordId: (_f = this.sessionContext) === null || _f === void 0 ? void 0 : _f.conversationId }, prechatRoutingAttributes),
            }),
        });
        if (!conversationResponse.ok) {
            throw new Error(`Conversation start failed: ${conversationResponse.status} ${conversationResponse.statusText}`);
        }
        // const conversationData: any = await conversationResponse.json()
        if (conversationResponse.ok) {
            this.sessionContext.conversationId = conversationId;
            ChatEventBus.emit("liveAgentReady", undefined);
            ChatEventBus.emit("AGENT_SESSION_INFO", {
                sessionId: this.sessionContext.accessToken,
                conversationId: this.sessionContext.conversationId,
            });
            // console.log(this.sessionContext?.initialMessages)
            // Send initial message to the agent here need to format the message properly
            // Iterate the initialmessages and create a user friendly display message with contact user: for user input and bot: as bot response
            let formatInitialMessages = "";
            if ((_h = (_g = this.sessionContext) === null || _g === void 0 ? void 0 : _g.extraPrechatFormDetails) === null || _h === void 0 ? void 0 : _h.length) {
                const prechatLines = this.sessionContext.extraPrechatFormDetails
                    .filter(detail => (detail === null || detail === void 0 ? void 0 : detail.label) && typeof detail.value === "string" && detail.value.trim() !== "" && detail.displayToAgent !== false)
                    .map(detail => `${detail.label}: ${detail.value}`);
                if (prechatLines.length > 0) {
                    formatInitialMessages += `Pre-chat details:\n${prechatLines.join("\n")}\n\n`;
                }
            }
            if (((_j = this.sessionContext) === null || _j === void 0 ? void 0 : _j.initialMessages) && ((_k = this.sessionContext) === null || _k === void 0 ? void 0 : _k.initialMessages.length) > 0) {
                (_l = this.sessionContext.initialMessages[0]) === null || _l === void 0 ? void 0 : _l.messages.forEach((message) => {
                    if (!(message === null || message === void 0 ? void 0 : message.text))
                        return;
                    // strip the <p> </p> tags from the message
                    message.text = message.text.replace(/<\/?p>/g, "");
                    if (message === null || message === void 0 ? void 0 : message.isUser) {
                        formatInitialMessages += `User: ${message.text}\n`;
                    }
                    else {
                        formatInitialMessages += `Bot: ${message.text}\n`;
                    }
                });
            }
            // console.log("Formatted Initial Messages", formatInitialMessages)
            if (formatInitialMessages) {
                this.sendMessage({ isNewSession: true, sessionId: ((_m = this.sessionContext) === null || _m === void 0 ? void 0 : _m.sessionId) || "", message: formatInitialMessages });
            }
            if (await this.checkAgentAvailability(this.sessionContext.conversationId || "")) {
                logger.debug("Agent is available, starting to listen to messages");
                this.listenToMessages();
            }
            else {
                // AGENT_UNAVAILABLE (with reason: failureReason | "timeout" | "request_error")
                // was already emitted by checkAgentAvailability
                logger.warn("No agent assigned — skipping SSE listener setup");
            }
        }
    }
    /**
     * Initializes the Salesforce Live Agent provider and starts listening for messages.
     * This should be called after the user has authenticated and is ready to start a chat session.
     */
    async initialize(startChatOptions) {
        var _a, _b, _c;
        logger.debug("Initializing Salesforce Live Agent Provider");
        if (!this.configSettings) {
            this.configSettings = (startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.config) || this.configSettings;
        }
        if (!((_a = this.configSettings) === null || _a === void 0 ? void 0 : _a.instanceUrl) || !((_b = this.configSettings) === null || _b === void 0 ? void 0 : _b.orgId) || !((_c = this.configSettings) === null || _c === void 0 ? void 0 : _c.messagingChannelId)) {
            throw new Error("Missing required configuration settings for Salesforce Live Agent Provider");
        }
        if (!this.sessionContext) {
            this.sessionContext = {
                accessToken: "",
                lastMessageReadTime: 0,
                sessionId: "",
                initialMessages: (startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.messageHistory) || [],
                isActive: false,
                conversationId: (startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.conversationId) || crypto.randomUUID().toLowerCase(),
                userId: (startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.userId) || "",
                extraPrechatFormDetails: (startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.extraPrechatFormDetails) || [],
            };
        }
        try {
            await this.authenticate();
            await this.startSession();
        }
        catch (error) {
            logger.error("Error initializing Salesforce Live Agent Provider:", error);
            throw error;
        }
    }
    parseMessageEntries(entries) {
        const filteredEntries = entries.filter(entry => {
            var _a, _b, _c, _d;
            return entry.entryType === "Message" && ((_c = (_b = (_a = entry.entryPayload) === null || _a === void 0 ? void 0 : _a.abstractMessage) === null || _b === void 0 ? void 0 : _b.staticContent) === null || _c === void 0 ? void 0 : _c.text) && ((_d = entry.sender) === null || _d === void 0 ? void 0 : _d.role) != "EndUser";
        });
        const mappedEntries = filteredEntries.map(entry => {
            const result = {
                id: entry.entryPayload.abstractMessage.id,
                content: entry.entryPayload.abstractMessage.staticContent.text,
                sender: {
                    role: this.mapSenderRole(entry.sender.role),
                    displayName: entry.senderDisplayName || "Unknown",
                },
                timestamp: entry.clientTimestamp,
            };
            return result;
        });
        return mappedEntries;
    }
    handleParticipantChange(event) {
        try {
            logger.debug("Participant change event received:", event.data);
            if (!event.data)
                return;
            // Parse the event data
            const data = JSON.parse(event.data);
            const entries = JSON.parse(data.conversationEntry.entryPayload).entries;
            let entryAddEventMessage = [];
            entries.forEach((entry) => {
                var _a, _b;
                const conId = crypto.randomUUID();
                if (entry.operation === "add" && entry.participant.role.toLowerCase() === "agent") {
                    entryAddEventMessage.push({
                        id: conId,
                        isUser: false,
                        conversationId: conId,
                        type: "system",
                        text: `${entry.displayName} has joined the chat`,
                        timestamp: new Date(),
                        sender: {
                            role: "agent",
                            displayName: (_a = entry === null || entry === void 0 ? void 0 : entry.displayName) !== null && _a !== void 0 ? _a : "System",
                        },
                    });
                }
                if (entry.operation === "remove" && entry.participant.role.toLowerCase() === "agent") {
                    entryAddEventMessage.push({
                        id: conId,
                        type: "system",
                        text: `${entry.displayName} has left the chat`,
                        conversationId: conId,
                        isUser: false,
                        timestamp: new Date(),
                        sender: {
                            role: "agent",
                            displayName: (_b = entry === null || entry === void 0 ? void 0 : entry.displayName) !== null && _b !== void 0 ? _b : "System",
                        },
                    });
                }
            });
            // return entryAddEventMessage ?? []
            if ((entryAddEventMessage === null || entryAddEventMessage === void 0 ? void 0 : entryAddEventMessage.length) > 0) {
                // Emit the event to notify the parent component
                ChatEventBus.emit("AGENT_EVENT", entryAddEventMessage);
            }
        }
        catch (error) {
            logger.error("Error handling participant change event:", error);
            // Handle error appropriately, e.g., log it or notify the user
        }
    }
    mapEntriesToMessages(entries) {
        const mappedEntries = entries.map((entry) => ({
            id: entry.entryPayload.abstractMessage.id,
            text: entry.entryPayload.abstractMessage.staticContent.text,
            sender: {
                role: this.mapSenderRole(entry.sender.role),
                displayName: entry.senderDisplayName || "Unknown",
            },
            type: entry.sender.role === "endUser" ? "user" : "ai",
            timestamp: new Date(entry.timestamp),
            isUser: false,
            conversationId: entry.entryPayload.abstractMessage.id,
        }));
        return mappedEntries;
    }
    handleParticipantMessage(event) {
        var _a, _b;
        try {
            if (!event.data)
                return;
            // Parse the event data
            const data = JSON.parse(event.data);
            /**
             * Ignore messages from EndUser role
             * This is to prevent processing messages that are not relevant to the agent's response
             */
            if (((_b = (_a = data === null || data === void 0 ? void 0 : data.conversationEntry) === null || _a === void 0 ? void 0 : _a.sender) === null || _b === void 0 ? void 0 : _b.role) === "EndUser") {
                logger.debug("Ignoring message from EndUser role");
                return;
            }
            const entryPayload = JSON.parse(data.conversationEntry.entryPayload);
            data.conversationEntry.entryPayload = entryPayload;
            const messageEntries = this.mapEntriesToMessages([data.conversationEntry]);
            if ((messageEntries === null || messageEntries === void 0 ? void 0 : messageEntries.length) > 0) {
                // Emit the event to notify the parent component
                ChatEventBus.emit("AGENT_MESSAGE", messageEntries);
            }
        }
        catch (error) {
            logger.error("Error handling participant message event:", error);
            // Handle error appropriately, e.g., log it or notify the user
        }
    }
    mapSenderRole(role) {
        const normalizedRole = role.toLowerCase();
        if (normalizedRole === "chatbot")
            return "agent";
        if (normalizedRole === "enduser")
            return "endUser";
        return "unknown";
    }
    handleSessionStatusChange(event) {
        try {
            if (!event.data)
                return;
            // Parse the event data
            const data = JSON.parse(event.data);
            const entryPayload = JSON.parse(data.conversationEntry.entryPayload);
            logger.debug("Session status changed:", entryPayload === null || entryPayload === void 0 ? void 0 : entryPayload.sessionStatus);
            if ((entryPayload === null || entryPayload === void 0 ? void 0 : entryPayload.sessionStatus) === "Active") {
                ChatEventBus.emit("AGENT_SESSION_CREATED", true);
            }
        }
        catch (error) {
            logger.error("Error handling session status change event:", error);
            // Handle error appropriately, e.g., log it or notify the user
        }
    }
    listenToMessages() {
        var _a, _b, _c;
        logger.debug("Listening to messages from Salesforce Live Agent");
        // this.endpointSSE = "http://localhost:5050"
        const eventSource = new EventSource(`${this.endpointSSE}/bot/liveagent/sse?token=${(_a = this.sessionContext) === null || _a === void 0 ? void 0 : _a.accessToken}&org_id=${(_b = this.configSettings) === null || _b === void 0 ? void 0 : _b.orgId}&sse_url=${(_c = this.configSettings) === null || _c === void 0 ? void 0 : _c.instanceUrl}`, {
            withCredentials: true,
        });
        if (!eventSource) {
            logger.error("Failed to create EventSource");
            throw new Error("Failed to create EventSource");
        }
        eventSource.onerror = () => {
            logger.error("❌ SSE Error: Connection lost or error occurred");
            // Handle error, e.g., retry connection or notify user
            ChatEventBus.emit("AGENT_ERROR", true);
            // Optionally, you can close the EventSource if needed
            eventSource.close();
        };
        eventSource.onopen = () => {
            logger.debug("✅ SSE Connection Established");
            // ChatEventBus.emit("liveAgentReady", undefined)
        };
        eventSource.onmessage = event => {
            var _a, _b;
            try {
                const parsedEventData = JSON.parse(event.data);
                logger.debug("📡 Message Received on entrytype:", (_a = parsedEventData === null || parsedEventData === void 0 ? void 0 : parsedEventData.conversationEntry) === null || _a === void 0 ? void 0 : _a.entryType, " --- ", event.data);
                // Handle incoming messages if needed
                switch ((_b = parsedEventData === null || parsedEventData === void 0 ? void 0 : parsedEventData.conversationEntry) === null || _b === void 0 ? void 0 : _b.entryType) {
                    case "RoutingResult":
                    case "RoutingWorkResult":
                        logger.debug("Conversation Routing Result:", event.data);
                        // Handle conversation routing result if needed
                        // ChatEventBus.emit("AGENT_SESSION_CREATED", true)
                        ChatEventBus.emit("FINDING_AGENT", event.data);
                        // ChatEventBus.emit("AGENT_EVENT", [])
                        break;
                    case "ParticipantChanged":
                        logger.debug("Conversation ParticipantChanged event received:", event === null || event === void 0 ? void 0 : event.data);
                        // Check if the participant joining is an AGENT, not the user
                        // ChatEventBus.emit("AGENT_SESSION_CREATED", true)
                        this.handleParticipantChange(event);
                        break;
                    case "Message":
                        this.handleParticipantMessage(event);
                        break;
                    case "CloseConversation":
                        ChatEventBus.emit("CONVERSATION_CLOSED", true);
                        eventSource.close();
                        break;
                    case "DeliveryAcknowledgement":
                    case "ReadAcknowledgement":
                        logger.debug("Conversation event received:", event === null || event === void 0 ? void 0 : event.data);
                        // Handle conversation close if needed
                        // ChatEventBus.emit("AGENT_EVENT", event.data)
                        break;
                    case "TypingStartedIndicator":
                        ChatEventBus.emit("TYPING_STARTED", true);
                        break;
                    case "TypingStoppedIndicator":
                        logger.debug("Typing indicator received:", event.data);
                        // Handle typing indicator if needed
                        ChatEventBus.emit("TYPING_STOPPED", true);
                        break;
                    case "StreamingToken":
                        logger.debug("Streaming token received", event.data);
                        // Handle streaming token if needed
                        // ChatEventBus.emit("streamingTokenReceived", event.data)
                        break;
                    case "ProgressIndicator":
                        logger.debug("Progress indicator received", event.data);
                        // Handle progress indicator if needed
                        // ChatEventBus.emit("progressIndicatorReceived", event.data)
                        break;
                    case "SessionStatusChanged":
                        logger.debug("Session status changed event received", event.data);
                        // Handle session status change if needed
                        this.handleSessionStatusChange(event);
                        break;
                    default:
                        // logger.warn("Unhandled conversation entry type:", parsedEventData.conversationEntry?.entryType)
                        break;
                }
            }
            catch (e) {
                logger.error("Failed to parse event data:", e);
                return;
            }
        };
    }
    /** Interface Implementation */
    /**
     * @param startChatOptions
     * @description This method initializes the Salesforce Live Agent provider and starts a chat session.
     * It authenticates with Salesforce, starts a new conversation, and sets up the session context.
     * It emits a "liveAgentReady" event when the session is successfully started.
     * @throws {Error} If initialization fails.
     * @returns {Promise<void>}
     * @memberof SalesforceLiveAgentProvider
     *
     *
     */
    async startChat(startChatOptions) {
        await this.initialize(startChatOptions);
    }
    /**
     * Resumes an existing live agent session using a stored access token and conversation ID.
     * Skips authentication and conversation creation — only reconnects the SSE listener.
     */
    async resumeChat(startChatOptions) {
        var _a, _b, _c;
        if (!(startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.sessionId) || !(startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.conversationId)) {
            throw new Error("resumeChat requires sessionId (accessToken) and conversationId");
        }
        this.configSettings = (startChatOptions === null || startChatOptions === void 0 ? void 0 : startChatOptions.config) || this.configSettings;
        if (!((_a = this.configSettings) === null || _a === void 0 ? void 0 : _a.instanceUrl) || !((_b = this.configSettings) === null || _b === void 0 ? void 0 : _b.orgId) || !((_c = this.configSettings) === null || _c === void 0 ? void 0 : _c.messagingChannelId)) {
            throw new Error("Missing required configuration settings for resuming Salesforce Live Agent session");
        }
        this.sessionContext = {
            accessToken: startChatOptions.sessionId,
            conversationId: startChatOptions.conversationId,
            userId: startChatOptions.userId || "",
            isActive: true,
            lastMessageReadTime: 0,
        };
        // Probe the session before declaring it ready
        const probeUrl = new URL(`${this.configSettings.instanceUrl}/iamessage/api/v2/conversation/${this.sessionContext.conversationId}/entries`);
        probeUrl.searchParams.set("limit", "1");
        probeUrl.searchParams.set("direction", "FromEnd");
        const probeRes = await fetch(probeUrl.toString(), {
            method: "GET",
            headers: { Authorization: `Bearer ${this.sessionContext.accessToken}` },
        });
        if (probeRes.status === 401 || probeRes.status === 403) {
            throw new LiveAgentAuthExpiredError();
        }
        if (!probeRes.ok) {
            throw new Error(`Session probe failed: ${probeRes.status} ${probeRes.statusText}`);
        }
        ChatEventBus.emit("liveAgentReady", undefined);
        this.listenToMessages();
    }
    /**
     *
     * @param sendMessageOptions
     * @description This method sends a message to the Salesforce Live Agent.
     * It constructs a POST request to the Salesforce MIAW API to send the message.
     * @throws {Error} If sending the message fails.
     * @returns {Promise<void>}
     * @memberof SalesforceLiveAgentProvider
     *
     */
    async sendMessage(sendMessageOptions) {
        var _a, _b, _c, _d;
        const res = await fetch(`${(_a = this.configSettings) === null || _a === void 0 ? void 0 : _a.instanceUrl}/iamessage/api/v2/conversation/${(_b = this.sessionContext) === null || _b === void 0 ? void 0 : _b.conversationId}/message`, {
            method: "POST",
            headers: {
                "Authorization": `Bearer ${(_c = this.sessionContext) === null || _c === void 0 ? void 0 : _c.accessToken}`,
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                message: {
                    id: crypto.randomUUID(),
                    messageType: "StaticContentMessage",
                    staticContent: {
                        formatType: "Text",
                        text: sendMessageOptions === null || sendMessageOptions === void 0 ? void 0 : sendMessageOptions.message,
                    },
                },
                esDeveloperName: (_d = this.configSettings) === null || _d === void 0 ? void 0 : _d.messagingChannelId,
                isNewMessagingSession: (sendMessageOptions === null || sendMessageOptions === void 0 ? void 0 : sendMessageOptions.isNewSession) || false,
                language: "",
            }),
        });
        if (!res.ok)
            throw new Error("Failed to send message");
    }
    /**
     *
     * @param _sessionId
     * @returns
     * @description This method polls for new messages in the Salesforce Live Agent conversation.
     * It sends a GET request to the Salesforce MIAW API to retrieve conversation entries.
     * It processes the entries and emits a "messageReceived" event with the new messages.
     * @throws {Error} If polling fails.
     * @returns {Promise<string[] | any>}
     * @memberof SalesforceLiveAgentProvider
     */
    async pollMessages(_sessionId) {
        return new Promise(async (resolve, reject) => {
            this.sessionContext.lastMessageReadTime = 0;
            const poll = async () => {
                var _a, _b, _c;
                try {
                    const url = new URL(`${(_a = this.configSettings) === null || _a === void 0 ? void 0 : _a.instanceUrl}/iamessage/api/v2/conversation/${(_b = this.sessionContext) === null || _b === void 0 ? void 0 : _b.conversationId}/entries`);
                    url.searchParams.append("limit", "50");
                    url.searchParams.append("direction", "FromEnd");
                    url.searchParams.append("startTimestamp", `${this.sessionContext.lastMessageReadTime}`);
                    const response = await fetch(url.toString(), {
                        method: "GET",
                        headers: {
                            Authorization: `Bearer ${(_c = this.sessionContext) === null || _c === void 0 ? void 0 : _c.accessToken}`,
                        },
                    });
                    const data = await response.json();
                    const unsortedEntries = this.parseMessageEntries(data.conversationEntries);
                    const sortedEntries = unsortedEntries.sort((a, b) => a.timestamp - b.timestamp);
                    const entries = sortedEntries.map(entry => {
                        var _a;
                        return ({
                            text: entry.content,
                            isUser: false,
                            id: entry.id,
                            timestamp: new Date(entry.timestamp),
                            images: [],
                            conversationId: entry.id,
                            formModel: "",
                            surveyDomId: "",
                            sender: {
                                role: entry.sender.role === "endUser" ? "user" : "ai",
                                displayName: (_a = entry === null || entry === void 0 ? void 0 : entry.sender) === null || _a === void 0 ? void 0 : _a.displayName,
                            },
                        });
                    });
                    if ((entries === null || entries === void 0 ? void 0 : entries.length) > 0) {
                        this.sessionContext.lastMessageReadTime = new Date().getTime();
                        ChatEventBus.emit("messageReceived", entries);
                    }
                    resolve(entries);
                    // No messages yet, poll again after delay
                    setTimeout(poll, 5000);
                }
                catch (err) {
                    logger.error("Error on Polling", err.toString());
                    reject(err);
                }
            };
            await poll();
        });
    }
    /**
     *
     * @param sessionId
     * @returns
     * @description This method checks if the chat session is active.
     * It checks the session context to determine if the session is active.
     */
    async isChatActive(sessionId) {
        logger.debug("sessionId", sessionId);
        if (!this.sessionContext)
            return false;
        return this.sessionContext.isActive;
    }
    /**
     *
     * @param sessionId
     * @description This method ends the chat session with Salesforce Live Agent.
     * It sends a POST request to the Salesforce MIAW API to close the conversation.
     */
    async endChat(_sessionId) {
        var _a, _b, _c, _d, _e, _f;
        (_a = this.availabilityAbort) === null || _a === void 0 ? void 0 : _a.abort();
        // console.log("this.sessionContext?.conversationId", this.sessionContext?.conversationId)
        if ((_b = this.sessionContext) === null || _b === void 0 ? void 0 : _b.conversationId) {
            const res = await fetch(`${(_c = this.configSettings) === null || _c === void 0 ? void 0 : _c.instanceUrl}/iamessage/api/v2/conversation/${(_d = this.sessionContext) === null || _d === void 0 ? void 0 : _d.conversationId}?esDeveloperName=${(_e = this.configSettings) === null || _e === void 0 ? void 0 : _e.messagingChannelId}`, {
                method: "DELETE",
                headers: {
                    "Authorization": `Bearer ${(_f = this.sessionContext) === null || _f === void 0 ? void 0 : _f.accessToken}`,
                    "Content-Type": "application/json",
                },
            });
            if (!(res === null || res === void 0 ? void 0 : res.ok)) {
                logger.warn(`Failed to end the chat`);
            }
        }
    }
    /**
     *
     * @param sessionId
     * @returns
     * @description This method retrieves the chat transcript for the given session ID.
     * It returns an array of messages from the session context.
     */
    async getTranscript(sessionId) {
        logger.debug("sessionId", sessionId);
        if (!this.sessionContext)
            return [];
        return this.sessionContext.initialMessages || [];
    }
}
