"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const __1 = require("..");
/**
 * Processes rich replies found in events. This automatically strips
 * the fallback representation from events, providing the information
 * as a top level "mx_richreply" key. The "mx_richreply" property may
 * be casted to the type IRichReplyMetadata.
 * @category Preprocessors
 */
class RichRepliesPreprocessor {
    /**
     * Creates a new rich replies preprocessor.
     * @param fetchRealEventContents If enabled, this preprocessor will
     * attempt to get the real event contents and append them to the event
     * information.
     */
    constructor(fetchRealEventContents = false) {
        this.fetchRealEventContents = fetchRealEventContents;
    }
    getSupportedEventTypes() {
        return ["m.room.message"];
    }
    processEvent(event, client) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!event["content"])
                return;
            if (!event["content"]["m.relates_to"])
                return;
            if (!event["content"]["m.relates_to"]["m.in_reply_to"])
                return;
            const parentEventId = event["content"]["m.relates_to"]["m.in_reply_to"]["event_id"];
            if (!parentEventId)
                return;
            let fallbackHtml = "";
            let fallbackText = "";
            let fallbackSender = "";
            let realHtml = event["content"]["formatted_body"];
            let realText = event["content"]["body"];
            let lenient = false;
            if (event["content"]["format"] !== "org.matrix.custom.html" || !event["content"]["formatted_body"]) {
                lenient = true; // Not safe to parse: probably not HTML
            }
            else {
                const formattedBody = event["content"]["formatted_body"];
                if (!formattedBody.startsWith("<mx-reply>") || formattedBody.indexOf("</mx-reply>") === -1) {
                    lenient = true; // Doesn't look like a reply
                }
                else {
                    const parts = formattedBody.split("</mx-reply>");
                    const fbHtml = parts[0];
                    realHtml = parts[1];
                    const results = fbHtml.match(/<br[ ]*[\/]{0,2}>(.*)<\/blockquote>\s*$/i);
                    if (!results) {
                        lenient = true;
                    }
                    else {
                        fallbackHtml = results[1];
                    }
                }
            }
            let lastLine = "";
            let processedFallback = false;
            const body = event["content"]["body"] || "";
            for (const line of body.split("\n")) {
                if (line.startsWith("> ") && !processedFallback) {
                    fallbackText += line.substring(2) + "\n";
                    lastLine = line;
                }
                else if (!processedFallback) {
                    lastLine = line;
                    realText = "";
                    processedFallback = true;
                }
                else {
                    realText += line + "\n";
                }
            }
            const firstFallbackLine = fallbackText.split("\n")[0];
            const matches = firstFallbackLine.match(/<(@.*:.*)>/);
            if (!matches) {
                lenient = true;
            }
            else {
                fallbackSender = matches[1];
            }
            const metadata = {
                wasLenient: lenient,
                fallbackHtmlBody: fallbackHtml ? fallbackHtml.trim() : "",
                fallbackPlainBody: fallbackText ? fallbackText.trim() : "",
                fallbackSender: fallbackSender ? fallbackSender.trim() : "",
                parentEventId: parentEventId ? parentEventId.trim() : "",
                realEvent: null,
            };
            if (this.fetchRealEventContents) {
                try {
                    metadata.realEvent = yield client.getEvent(event["room_id"], parentEventId);
                }
                catch (e) {
                    __1.LogService.error("RichRepliesPreprocessor", "Failed to fetch real event:");
                    __1.LogService.error("RichRepliesPreprocessor", e);
                    metadata.wasLenient = true; // failed to fetch event
                }
            }
            event["mx_richreply"] = metadata;
            event["content"]["body"] = realText.trim();
            event["content"]["formatted_body"] = realHtml.trim();
            return event;
        });
    }
}
exports.RichRepliesPreprocessor = RichRepliesPreprocessor;
