// NymDrop — minimal self-hosted Markdown preview for the message field.
// No external library: a small, auditable subset is enough for a
// submission form, and it avoids pulling a third-party JS dependency into
// a page whose whole point is minimizing trust in client-side code.
//
// The rendered HTML never leaves the browser — the encrypted submission
// still carries the raw Markdown source text untouched (see app.js). This
// is purely a "what will this look like" aid for the person writing it.

function mdEscapeHtml(str) {
    return str
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#39;");
}

// Only allow link schemes that can't execute script in the rendered preview.
function mdSafeHref(url) {
    if (/^(https?:|mailto:)/i.test(url)) return mdEscapeHtml(url);
    return "#";
}

function mdInline(text) {
    let out = mdEscapeHtml(text);
    out = out.replace(/`([^`]+)`/g, "<code>$1</code>");
    out = out.replace(/\*\*([^*]+)\*\*|__([^_]+)__/g, (m, a, b) => `<strong>${a || b}</strong>`);
    out = out.replace(/\*([^*]+)\*|_([^_]+)_/g, (m, a, b) => `<em>${a || b}</em>`);
    out = out.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (m, label, url) =>
        `<a href="${mdSafeHref(url)}" target="_blank" rel="noopener noreferrer">${label}</a>`);
    return out;
}

function renderMarkdown(source) {
    const lines = source.replace(/\r\n/g, "\n").split("\n");
    const html = [];
    let i = 0;
    let para = [];

    function flushPara() {
        if (para.length) {
            html.push("<p>" + para.map(mdInline).join("<br>") + "</p>");
            para = [];
        }
    }

    while (i < lines.length) {
        const line = lines[i];

        if (/^```/.test(line)) {
            flushPara();
            const code = [];
            i++;
            while (i < lines.length && !/^```/.test(lines[i])) {
                code.push(lines[i]);
                i++;
            }
            html.push("<pre><code>" + mdEscapeHtml(code.join("\n")) + "</code></pre>");
            i++;
            continue;
        }

        const heading = line.match(/^(#{1,3})\s+(.*)$/);
        if (heading) {
            flushPara();
            const level = heading[1].length;
            html.push(`<h${level}>${mdInline(heading[2])}</h${level}>`);
            i++;
            continue;
        }

        if (/^(---|\*\*\*)\s*$/.test(line)) {
            flushPara();
            html.push("<hr>");
            i++;
            continue;
        }

        if (/^>\s?/.test(line)) {
            flushPara();
            const quote = [];
            while (i < lines.length && /^>\s?/.test(lines[i])) {
                quote.push(lines[i].replace(/^>\s?/, ""));
                i++;
            }
            html.push("<blockquote>" + renderMarkdown(quote.join("\n")) + "</blockquote>");
            continue;
        }

        if (/^[-*]\s+/.test(line)) {
            flushPara();
            const items = [];
            while (i < lines.length && /^[-*]\s+/.test(lines[i])) {
                items.push(`<li>${mdInline(lines[i].replace(/^[-*]\s+/, ""))}</li>`);
                i++;
            }
            html.push("<ul>" + items.join("") + "</ul>");
            continue;
        }

        if (/^\d+\.\s+/.test(line)) {
            flushPara();
            const items = [];
            while (i < lines.length && /^\d+\.\s+/.test(lines[i])) {
                items.push(`<li>${mdInline(lines[i].replace(/^\d+\.\s+/, ""))}</li>`);
                i++;
            }
            html.push("<ol>" + items.join("") + "</ol>");
            continue;
        }

        if (line.trim() === "") {
            flushPara();
            i++;
            continue;
        }

        para.push(line);
        i++;
    }
    flushPara();

    return html.join("\n");
}

(function() {
    const textarea = document.getElementById("message");
    const preview = document.getElementById("message-preview");
    const toggle = document.getElementById("preview-toggle");
    if (!textarea || !preview || !toggle) return;

    let showingPreview = false;

    toggle.addEventListener("click", function() {
        showingPreview = !showingPreview;
        if (showingPreview) {
            preview.innerHTML = renderMarkdown(textarea.value) ||
                '<p class="md-empty">Nothing to preview yet.</p>';
            textarea.hidden = true;
            preview.hidden = false;
            toggle.textContent = "Edit";
        } else {
            preview.hidden = true;
            textarea.hidden = false;
            toggle.textContent = "Preview";
        }
    });
})();
