//------------------------------------------------ユーズ表示系関数--------------------------------------------------
var global_userid;
var account_id;

function view_ueuse_init(user_id, loginid) {
    global_userid = user_id;
    global_account_id = loginid;
    return true;
}

const mentionCache = {};
const fetchingMentions = false;

async function replaceMentions(text) {
    const placeholders = [];
    let index = 0;

    // aタグの一時置き換え
    text = text.replace(/<a\b[^>]*>.*?<\/a>/gi, (match) => {
        const placeholder = `\u2063{{PLACEHOLDER${index}}}\u2063`;
        placeholders.push(match);
        index++;
        return placeholder;
    });

    const mentionMatches = [...text.matchAll(/@([a-zA-Z0-9_]+)/g)];
    if (mentionMatches.length === 0) {
        placeholders.forEach((original, i) => {
            text = text.replace(`\u2063{{PLACEHOLDER${i}}}\u2063`, original);
        });
        return text;
    }

    // ユーザーIDを小文字に正規化
    const uniqueMentions = [...new Set(mentionMatches.map(match => match[1]))];
    const mentionsToFetch = uniqueMentions.filter(userID => !mentionCache[userID]);

    if (mentionsToFetch.length > 0) {
        await new Promise((resolve) => {
            $.ajax({
                url: '../function/get_userid.php',
                method: 'POST',
                data: {
                    get_account: mentionsToFetch.join(','),
                    userid: global_userid,
                    account_id: global_account_id
                },
                dataType: 'json',
                timeout: 300000,
                success: function (response) {
                    if (response.success && response.users) {
                        for (const [name, userInfo] of Object.entries(response.users)) {
                            if (userInfo && userInfo.userid && userInfo.username) {
                                mentionCache[name] = `<a href="/@${userInfo.userid}" class="mta">@${userInfo.username}</a>`;
                            } else {
                                mentionCache[name] = `@${name}`;
                            }
                        }
                    }
                    resolve();
                },
                error: function () {
                    for (const name of mentionsToFetch) {
                        mentionCache[name] = `@${name}`;
                    }
                    resolve();
                }
            });
        });
    }

    // 元のtextに適用（小文字で照合）
    text = text.replace(/@([a-zA-Z0-9_]+)/g, (_, id) => {
        const lower = id;
        return mentionCache[lower] || `@${id}`; // 表示は元の大文字小文字を保持
    });

    // aタグ戻す
    placeholders.forEach((original, i) => {
        text = text.replace(`\u2063{{PLACEHOLDER${i}}}\u2063`, original);
    });

    return text;
}

const CACHE_KEY = 'emojiCache';
const CACHE_EXPIRY_KEY = 'emojiCacheExpiry';
const CACHE_LIFETIME_MS = 24 * 60 * 60 * 1000; // 24時間

let emojiCache = {};
let fetchingEmojis = {};

(function loadEmojiCache() {
    const savedCache = localStorage.getItem(CACHE_KEY);
    const savedExpiry = localStorage.getItem(CACHE_EXPIRY_KEY);

    if (savedCache && savedExpiry && Date.now() < Number(savedExpiry)) {
        try {
            emojiCache = JSON.parse(savedCache);
        } catch (e) {
            localStorage.removeItem(CACHE_KEY);
            localStorage.removeItem(CACHE_EXPIRY_KEY);
        }
    } else {
        localStorage.removeItem(CACHE_KEY);
        localStorage.removeItem(CACHE_EXPIRY_KEY);
    }
})();

function saveEmojiCache() {
    localStorage.setItem(CACHE_KEY, JSON.stringify(emojiCache));
    localStorage.setItem(CACHE_EXPIRY_KEY, (Date.now() + CACHE_LIFETIME_MS).toString());
}

async function replaceCustomEmojis(text) {
    const emojiMatches = [...text.matchAll(/:([a-zA-Z0-9_]+):/g)];
    if (emojiMatches.length === 0) return text;

    const uniqueEmojis = [...new Set(emojiMatches.map(match => match[1]))];
    const emojisToFetch = uniqueEmojis.filter(name => !emojiCache[name] && !fetchingEmojis[name]);

    if (emojisToFetch.length > 0) {
        const fetchPromise = new Promise((resolve) => {
            $.ajax({
                url: '../function/get_customemoji.php',
                method: 'POST',
                data: {
                    emoji: emojisToFetch.join(','),
                    userid: global_userid,
                    account_id: global_account_id
                },
                dataType: 'json',
                timeout: 30000,
                success: function (response) {
                    if (response.success && response.emojis) {
                        for (const name of emojisToFetch) {
                            if (response.success && response.emojis) {
                                for (const name of emojisToFetch) {
                                    if (response.emojis[name]) {
                                        const emoji = response.emojis[name];
                                        emojiCache[name] = emoji.emojipath;
                                    } else {
                                        emojiCache[name] = null;
                                    }
                                }
                            }
                        }
                    } else {
                        for (const name of emojisToFetch) {
                            emojiCache[name] = null;
                        }
                    }
                    saveEmojiCache();
                    resolve();
                },
                error: function () {
                    for (const name of emojisToFetch) {
                        emojiCache[name] = null;
                    }
                    saveEmojiCache();
                    resolve();
                }
            });
        });

        emojisToFetch.forEach(name => {
            fetchingEmojis[name] = fetchPromise;
        });

        await fetchPromise;
    }

    await Promise.all(uniqueEmojis.map(name => fetchingEmojis[name]));

    text = text.replace(/:([a-zA-Z0-9_]+):/g, (_, name) => {
        const url = emojiCache[name];
        if (url === undefined) return `:${name}:`; // 未取得
        if (url === null) return `:${name}:`;       // 存在しない

        return `<img src="${url}" alt=":${name}:">`; // ここで生成
    });

    return text;
}

function a_link(text) {
    const placeholders = {};
    let placeholderIndex = 0;

    text = text.replace(/&#039;/g, (match) => {
        const key = `\u2063{{PLACEHOLDER${placeholderIndex++}}}\u2063`;
        placeholders[key] = match; // 元の文字列を保存
        return key;
    });

    text = text.replace(/(https:\/\/[\w!?\/+\-_~;.,*&@#$%()+|https:\/\/[ぁ-んァ-ヶ一ー-龠々\w\-\/?=&%.]+)/g, function (url) {
        const escapedUrl = url;
        const no_https_link = escapedUrl.replace("https://", "");
        if (no_https_link.length > 48) {
            const truncatedLink = no_https_link.substring(0, 48) + '...';
            return `<a href="${escapedUrl}" target="_blank" rel="noopener">${truncatedLink}</a>`;
        } else {
            return `<a href="${escapedUrl}" target="_blank" rel="noopener">${no_https_link}</a>`;
        }
    });

    text = text.replace(/(^|[^a-zA-Z0-9_])#([a-zA-Z0-9ぁ-んァ-ン一-龥ー_]+)/gu, function (match, before, tag) {
        const encodedTag = encodeURIComponent("#" + tag);
        return `${before}<a href="/search?q=${encodedTag}" class="hashtags">#${tag}</a>`;
    });

    for (const key in placeholders) {
        const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        text = text.replace(new RegExp(escapedKey, 'g'), placeholders[key]);
    }

    return text;
}

function formatMarkdown(text) {
    const placeholders = {};
    let placeholderIndex = 0;

    // URLをプレースホルダーに退避
    text = text.replace(/<a\b[^>]*>[\s\S]*?<\/a>/g, (match) => {
        const key = `\u2063{{PLACEHOLDER${placeholderIndex++}}}\u2063`;
        placeholders[key] = match; // 元の文字列を保存
        return key;
    });

    // 複数行インラインコード（バッククォート3つ）を検出して、<pre><code>で囲む
    text = text.replace(/```([\s\S]+?)```/g, (match, code) => {
        const key = `\u2063{{PLACEHOLDER${placeholderIndex++}}}\u2063`;
        placeholders[key] = `<pre class="codeblock"><code>${code.replace(/^\s*\n/, '')}</code></pre>`;
        return key;
    });

    // コードブロックの退避
    text = text.replace(/`([^`\n]+)`/g, (_, code) => {
        const key = `\u2063{{PLACEHOLDER${placeholderIndex++}}}\u2063`;
        placeholders[key] = `<span class="inline">${code}</span>`;
        return key;
    });

    // コロンで囲まれた絵文字をプレースホルダーに退避
    text = text.replace(/:([a-zA-Z0-9_]+):/g, (match) => {
        const key = `\u2063{{PLACEHOLDER${placeholderIndex++}}}\u2063`;
        placeholders[key] = match; // 元の文字列を保存
        return key;
    });

    // ユーザーIDをプレースホルダーに退避
    text = text.replace(/@([a-zA-Z0-9_]+)/g, (match) => {
        const key = `\u2063{{PLACEHOLDER${placeholderIndex++}}}\u2063`;
        placeholders[key] = match; // 元の文字列を保存
        return key;
    });

    // 独自構文などの装飾
    text = text.replace(/\[\[buruburu (.+?)\]\]/g, '<span class="buruburu">$1</span>');
    text = text.replace(/\[\[time (\d+)\]\]/g, (_, ts) => {
        const d = new Date(parseInt(ts, 10) * 1000);
        return `<span class="unixtime" title="${d.toLocaleString()}">${d.toLocaleString()}</span>`;
    });

    // マークダウン風装飾
    text = text
        .replace(/\*\*\*(.+?)\*\*\*/g, '<b><i>$1</i></b>')
        .replace(/___(.+?)___/g, '<b><i>$1</i></b>')
        .replace(/\*\*(.+?)\*\*/g, '<b>$1</b>')
        .replace(/__(.+?)__/g, '<b>$1</b>')
        .replace(/\*(.+?)\*/g, '<i>$1</i>')
        .replace(/_(.+?)_/g, '<i>$1</i>')
        .replace(/~~(.+?)~~/g, '<s>$1</s>')
        .replace(/^&gt;&gt;&gt; ?(.*)$/gm, '<span class="quote">$1</span>')  // ここを修正
        .replace(/\|\|(.+?)\|\|/g, '<span class="blur">$1</span>')
        .replace(/^# (.+)/gm, '<h1>$1</h1>')
        .replace(/^## (.+)/gm, '<h2>$1</h2>')
        .replace(/^### (.+)/gm, '<h3>$1</h3>')
        .replace(/^- (.+)/gm, '・ $1');

    // 行ごとに <p> タグで囲む
    const lines = text.split('\n').map(line => {
        line = line.trim();
        return line === '' ? '<br>' : `<p>${line}</p>`;
    });

    // プレースホルダーを戻す
    let final = lines.join('');
    for (const key in placeholders) {
        const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        final = final.replace(new RegExp(escapedKey, 'g'), placeholders[key]);
    }

    return final;
}

function YouTube_and_nicovideo_Links(postText) {
    const urlPattern = /(https:\/\/[^\s<>\[\]'"“”]+)/g;
    const urls = postText.match(urlPattern);
    let embedCode = '';

    if (!urls) return null;

    let embeddedOnce = false; // ← 埋め込みが1回されたかどうか

    urls.forEach(url => {
        if (embeddedOnce) return; // ← すでに埋め込みしたらスキップ

        try {
            const parsed = new URL(url);
            const host = parsed.hostname.replace(/^www\./, '');
            let videoId = '';
            let videoTime = '0';
            let iframe = false;

            if (['youtube.com', 'youtu.be', 'm.youtube.com'].includes(host)) {
                if (parsed.hostname === 'youtu.be') {
                    videoId = parsed.pathname.replace('/', '');
                    iframe = true;
                } else if (parsed.searchParams.has('v')) {
                    videoId = parsed.searchParams.get('v');
                    iframe = true;
                } else if (parsed.pathname.startsWith('/shorts/')) {
                    videoId = parsed.pathname.replace('/shorts/', '');
                    iframe = true;
                }

                if (parsed.searchParams.has('t') || parsed.searchParams.has('start')) {
                    videoTime = parsed.searchParams.get('t') || parsed.searchParams.get('start') || '0';
                    if (isNaN(parseInt(videoTime))) videoTime = '0';
                }

                if (iframe && videoId) {
                    embedCode = `<div class="youtube_and_nicovideo_player"><iframe src="https://www.youtube-nocookie.com/embed/${videoId}?start=${videoTime}" rel="0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe></div>`;
                    embeddedOnce = true;
                }

            } else if (['nicovideo.jp', 'nico.ms'].includes(host)) {
                if (parsed.pathname.includes('/watch/')) {
                    videoId = parsed.pathname.split('/watch/')[1];
                    iframe = true;
                } else {
                    videoId = parsed.pathname.replace('/', '');
                    iframe = true;
                }

                if (parsed.searchParams.has('from')) {
                    videoTime = parsed.searchParams.get('from');
                    if (isNaN(parseInt(videoTime))) videoTime = '0';
                }

                if (iframe && videoId) {
                    embedCode = `<div class="youtube_and_nicovideo_player"><iframe src="https://embed.nicovideo.jp/watch/${videoId}?from=${videoTime}" frameborder="0" allowfullscreen></iframe></div>`;
                    embeddedOnce = true;
                }
            } else {
                embedCode = null
            }
        } catch (e) {
            // 無視
        }
    });

    return embedCode;
}


function formatSmartDate(datetimeStr) {
    const date = new Date(datetimeStr.replace(" ", "T"));
    const now = new Date();
    const diffMs = now - date;
    const diffAbs = Math.abs(diffMs);
    const future = diffMs < 0;

    const pad = (n) => n.toString().padStart(2, '0');
    const hhmm = `${pad(date.getHours())}:${pad(date.getMinutes())}`;

    const y = date.getFullYear();
    const m = date.getMonth();
    const d = date.getDate();

    const nowY = now.getFullYear();
    const nowM = now.getMonth();
    const nowD = now.getDate();

    const dayDiff = Math.floor((new Date(y, m, d) - new Date(nowY, nowM, nowD)) / (1000 * 60 * 60 * 24));

    if (!future && diffAbs < 30 * 1000) return "今";
    if (future && diffAbs < 60 * 1000) return "まもなく";
    if (future && diffAbs < 60 * 60 * 1000) return `${Math.floor(diffAbs / 1000 / 60)}分後`;

    if (dayDiff === 0) return `今日 ${hhmm}`;
    if (dayDiff === 1) return `明日 ${hhmm}`;

    if (!future && y === nowY && m === 0 && d === 1) return `元日 ${hhmm}`;

    if (y === nowY) return `${pad(m + 1)}/${pad(d)} ${hhmm}`;

    return `${y}/${pad(m + 1)}/${pad(d)} ${hhmm}`;
}

function getCheckIcon(userdata) {
    if (userdata["role"] && userdata["role"].includes("official")) {
        return `<div class="checkicon"><div class="check"></div></div>`;
    }
    return "";
}

function getBotIcon(userdata) {
    if (userdata["is_bot"] && userdata["is_bot"] == true) {
        return `<div class="bot">Bot</div>`;
    }
    return "";
}

async function createUeuseHtml(ueuse, selectedUniqid = null) {
    let html = "";
    let check = "";
    let bot = "";
    var reuse = "";
    let contentHtml = "";

    var uniqid = "";
    var userid = "";
    var username = "";
    var iconurl = "";
    var datetime = "";
    var favoritecount = 0;
    var replycount = 0;
    var reusecount = 0;
    var is_favorite = false;
    var is_bookmark = false;
    var is_nsfw = false;
    var abi = "";
    var abi_date = "";
    var abi_html = "";
    var addabi = "";
    var inyo = "";
    var img1 = "";
    var img2 = "";
    var img3 = "";
    var img4 = "";
    var vid1 = "";
    var img_html = "";
    var vid_html = "";
    var nsfw_html = "";
    var nsfw_start_html = "";
    var nsfw_end_html = "";

    if (ueuse["type"] == "Reuse") {
        if (ueuse["reuse"]) {
            check = getCheckIcon(ueuse["userdata"]);
            bot = getBotIcon(ueuse["userdata"]);
        }

        if (ueuse["ueuse"].length > 0) {
            reuse = ``;
            if (!(ueuse["reuse"] == null)) {
                // カスタム絵文字を非同期に差し替え
                var inyoreuseHtml = formatMarkdown(a_link(ueuse["reuse"]["ueuse"]));
                inyoreuseHtml = await replaceMentions(inyoreuseHtml);
                inyoreuseHtml = await replaceCustomEmojis(inyoreuseHtml);

                inyo = `<div class="reuse_box" data-uniqid="` + ueuse["reuse"]["uniqid"] + `" id="quote_reuse">
                            <div class="reuse_flebox">
                                <a href="/!`+ ueuse["reuse"]["uniqid"] + `">
                                    <img src="`+ ueuse["reuse"]["userdata"]["iconurl"] + `">
                                </a>
                                <a href="/!`+ ueuse["reuse"]["uniqid"] + `">
                                    <div class="u_name">
                                        `+ await replaceCustomEmojis(ueuse["reuse"]["userdata"]["username"]) + `
                                    </div>
                                </a>
                                <div class="idbox">
                                    <a href="/@`+ ueuse["reuse"]["userdata"]["userid"] + `">
                                        @`+ ueuse["reuse"]["userdata"]["userid"] + `
                                    </a>
                                </div>
                            </div>

                            <p>
                                `+ inyoreuseHtml + `
                            </p>
                        </div>`;
            } else {
                inyo = `<div class="reuse_box" id="quote_reuse">
                            <p>
                                リユーズ元のユーズは削除されました。
                            </p>
                        </div>`;
            }

            contentHtml = formatMarkdown(a_link(ueuse["ueuse"]));

            uniqid = ueuse["uniqid"];
            userid = ueuse["userdata"]["userid"];
            username = ueuse["userdata"]["username"];
            iconurl = ueuse["userdata"]["iconurl"];
            datetime = ueuse["datetime"];
            favoritecount = ueuse["favoritecount"];
            replycount = ueuse["replycount"];
            reusecount = ueuse["reusecount"];
            is_favorite = ueuse["is_favorite"];
            is_bookmark = ueuse["is_bookmark"];

            is_nsfw = ueuse["nsfw"];

            img1 = ueuse["photo1"];
            img2 = ueuse["photo2"];
            img3 = ueuse["photo3"];
            img4 = ueuse["photo4"];
            vid1 = ueuse["video1"];

            abi = ueuse["abi"]["abi_text"];
            abi_date = ueuse["abi"]["abi_date"];
        } else {
            if (!(ueuse["reuse"] == null)) {
                reuse = `<div class="ru">
                            <a href="/@`+ ueuse["userdata"]["userid"] + `">
                                <img src="`+ ueuse["userdata"]["iconurl"] + `">
                                <p>`+ await replaceCustomEmojis(ueuse["userdata"]["username"]) + `さんがリユーズ</p>
                            </a>
                        </div>`;
                inyo = ``;
                contentHtml = formatMarkdown(a_link(ueuse["reuse"]["ueuse"]));

                uniqid = ueuse["reuse"]["uniqid"];
                userid = ueuse["reuse"]["userdata"]["userid"];
                username = ueuse["reuse"]["userdata"]["username"];
                iconurl = ueuse["reuse"]["userdata"]["iconurl"];
                datetime = ueuse["reuse"]["datetime"];
                favoritecount = ueuse["reuse"]["favoritecount"];
                replycount = ueuse["reuse"]["replycount"];
                reusecount = ueuse["reuse"]["reusecount"];
                is_favorite = ueuse["reuse"]["is_favorite"];
                is_bookmark = ueuse["reuse"]["is_bookmark"];

                is_nsfw = ueuse["reuse"]["nsfw"];

                img1 = ueuse["reuse"]["photo1"];
                img2 = ueuse["reuse"]["photo2"];
                img3 = ueuse["reuse"]["photo3"];
                img4 = ueuse["reuse"]["photo4"];
                vid1 = ueuse["reuse"]["video1"];

                abi = ueuse["reuse"]["abi"]["abi_text"];
                abi_date = ueuse["reuse"]["abi"]["abi_date"];
            } else {
                reuse = `<div class="ru">
                            <a href="/@`+ ueuse["userdata"]["userid"] + `">
                                <img src="`+ ueuse["userdata"]["iconurl"] + `">
                                <p>`+ await replaceCustomEmojis(ueuse["userdata"]["username"]) + `さんがリユーズ</p>
                            </a>
                        </div>`;
                inyo = ``;
                contentHtml = "リユーズ元のユーズは削除されました。";

                uniqid = ueuse["uniqid"];
                userid = ueuse["userdata"]["userid"];
                username = ueuse["userdata"]["username"];
                iconurl = ueuse["userdata"]["iconurl"];
                datetime = ueuse["datetime"];
                favoritecount = ueuse["favoritecount"];
                replycount = ueuse["replycount"];
                reusecount = ueuse["reusecount"];
                is_favorite = ueuse["is_favorite"];
                is_bookmark = ueuse["is_bookmark"];

                is_nsfw = ueuse["nsfw"];

                img1 = ueuse["photo1"];
                img2 = ueuse["photo2"];
                img3 = ueuse["photo3"];
                img4 = ueuse["photo4"];
                vid1 = ueuse["video1"];

                abi = ueuse["abi"]["abi_text"];
                abi_date = ueuse["abi"]["abi_date"];
            }
        }

    } else if (ueuse["type"] == "Reply") {
        check = getCheckIcon(ueuse["userdata"]);
        bot = getBotIcon(ueuse["userdata"]);

        if (selectedUniqid != null && selectedUniqid == ueuse["uniqid"]) {
            reuse = `<div class="rp"><div class="here"></div><div class="totop"></div><p>一番上のユーズに返信</p></div>`;
        } else {
            reuse = `<div class="rp"><div class="totop"></div><p>一番上のユーズに返信</p></div>`;
        }

        inyo = ``;
        contentHtml = formatMarkdown(a_link(ueuse["ueuse"]));

        uniqid = ueuse["uniqid"];
        userid = ueuse["userdata"]["userid"];
        username = ueuse["userdata"]["username"];
        iconurl = ueuse["userdata"]["iconurl"];
        datetime = ueuse["datetime"];
        favoritecount = ueuse["favoritecount"];
        replycount = ueuse["replycount"];
        reusecount = ueuse["reusecount"];
        is_favorite = ueuse["is_favorite"];
        is_bookmark = ueuse["is_bookmark"];

        is_nsfw = ueuse["nsfw"];

        img1 = ueuse["photo1"];
        img2 = ueuse["photo2"];
        img3 = ueuse["photo3"];
        img4 = ueuse["photo4"];
        vid1 = ueuse["video1"];

        abi = ueuse["abi"]["abi_text"];
        abi_date = ueuse["abi"]["abi_date"];
    } else if (ueuse["type"] == "User") {
        html = `
            <div class="ueuse">
                <div class="headbox">
                    <a href="/@`+ ueuse["userdata"]["userid"] + `">
                        <img src="`+ ueuse["userdata"]["headurl"] + `">
                    </a>
                </div>
                <div class="flebox">
                    <div class="user">
                        <a href="/@`+ ueuse["userdata"]["userid"] + `">
                            <img src="`+ ueuse["userdata"]["iconurl"] + `">
                        </a>
                        <div class="u_name">
                            <a href="/@`+ ueuse["userdata"]["userid"] + `">` + ueuse["userdata"]["username"] + `</a>
                        </div>
                        <div class="idbox">
                            <a href="/@`+ ueuse["userdata"]["userid"] + `">@` + ueuse["userdata"]["userid"] + `</a>
                        </div>
                    </div>
                </div>
                
                <div class="profilebox">
                    <p>
                    `+ ueuse["userdata"]["profile"] + `
                    </p>
                </div>
            </div>
        `;
        return html;
    } else {
        check = getCheckIcon(ueuse["userdata"]);
        bot = getBotIcon(ueuse["userdata"]);

        reuse = ``;
        inyo = ``;
        contentHtml = formatMarkdown(a_link(ueuse["ueuse"]));

        uniqid = ueuse["uniqid"];
        userid = ueuse["userdata"]["userid"];
        username = ueuse["userdata"]["username"];
        iconurl = ueuse["userdata"]["iconurl"];
        datetime = ueuse["datetime"];
        favoritecount = ueuse["favoritecount"];
        replycount = ueuse["replycount"];
        reusecount = ueuse["reusecount"];
        is_favorite = ueuse["is_favorite"];
        is_bookmark = ueuse["is_bookmark"];

        is_nsfw = ueuse["nsfw"];

        img1 = ueuse["photo1"];
        img2 = ueuse["photo2"];
        img3 = ueuse["photo3"];
        img4 = ueuse["photo4"];
        vid1 = ueuse["video1"];

        abi = ueuse["abi"]["abi_text"];
        abi_date = ueuse["abi"]["abi_date"];
    }

    if (abi != "" && typeof abi === "string") {
        abi = formatMarkdown(a_link(abi));
        abi = await replaceMentions(abi);
        abi = await replaceCustomEmojis(abi);

        abi_html = `<div class="abi">
                        <div class="back">
                        <h1>`+ await replaceCustomEmojis(username) + `さんが追記しました</h1>
                        </div><p>`+ abi + `</p>
                        <div class="h3s">`+ formatSmartDate(abi_date) + `</div>
                    </div>`;
        addabi = ``;
    } else {
        abi_html = ``;
        if (global_userid == userid) {
            addabi = `<button name="addabi" id="addabi" data-uniqid2="` + uniqid + `" class="addabi"><svg><use xlink:href="../img/sysimage/addabi_1.svg#addabi_1"></use></svg></button>`;
        } else {
            addabi = ``;
        }
    }

    let is_fav = {
        "class": "favbtn",
        "icon": "../img/sysimage/favorite_1.svg#favorite"
    };
    if (is_favorite === true) {
        is_fav = {
            "class": "favbtn favbtn_after",
            "icon": "../img/sysimage/favorite_2.svg#favorite"
        };
    }

    let is_reu = {
        "class": "reuse"
    };
    if (ueuse["type"] == "Reuse") {
        if (!(ueuse["ueuse"].length > 0)) {
            if (global_userid == ueuse["userdata"]["userid"]) {
                is_reu = {
                    "class": "reuse reuse_after"
                };
            }
        }
    }

    let is_bok = {
        "class": "bookmark",
        "icon": "../img/sysimage/bookmark_1.svg#bookmark_1"
    };
    if (is_bookmark === true) {
        is_bok = {
            "class": "bookmark bookmark_after",
            "icon": "../img/sysimage/bookmark_1.svg#bookmark_1"
        };
    }

    if (is_nsfw == true) {
        nsfw_html = `<div class="nsfw" data-uniqid="` + uniqid + `" id="nsfw">
                        <p>NSFW指定がされている投稿です！<br>職場や公共の場での表示には適さない場合があります。<br>表示ボタンを押すと表示されます。</p>
                        <div class="btnzone">
                            <input type="button" id="nsfw_view" class="mini_irobtn" value="表示">
                        </div>
                    </div>`
        nsfw_start_html = `<div class="nsfw_main" data-uniqid="` + uniqid + `"><div class="block">`
        nsfw_end_html = `</div></div>`
    }

    if (img1.length > 0) {
        if (img2.length > 0) {
            if (img3.length > 0) {
                if (img4.length > 0) {
                    img_html = `<div class="photo4">
                        <a>
                            <img src="`+ img1 + `" alt="画像1" title="画像1" data-id="1" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                        </a>
                        <a>
                            <img src="`+ img2 + `" alt="画像2" title="画像2" data-id="2" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                        </a>
                        <a>
                            <img src="`+ img3 + `" alt="画像3" title="画像3" data-id="3" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                        </a>
                        <a>
                            <img src="`+ img4 + `" alt="画像4" title="画像4" data-id="4" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                        </a>
                    </div>`;
                } else {
                    img_html = `<div class="photo3">
                                    <a>
                                        <img src="`+ img1 + `" alt="画像1" title="画像1" data-id="1" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                                    </a>
                                    <a>
                                        <img src="`+ img2 + `" alt="画像2" title="画像2" data-id="2" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                                    </a>
                                    <div class="photo3_btm">
                                        <a>
                                            <img src="`+ img3 + `" alt="画像3" title="画像3" data-id="3" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                                        </a>
                                    </div>
                                </div>`;
                }
            } else {
                img_html = `<div class="photo2">
                                <a>
                                    <img src="`+ img1 + `" alt="画像1" title="画像1" data-id="1" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                                </a>
                                <a>
                                    <img src="`+ img2 + `" alt="画像2" title="画像2" data-id="2" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                                </a>
                            </div>`;
            }
        } else {
            img_html = `<div class="photo1">
                            <a>
                                <img src="`+ img1 + `" alt="画像1" title="画像1" data-id="1" id="ueuse_image" onerror="this.onerror=null;this.src='../img/sysimage/errorimage/image_404.png'">
                            </a>
                        </div>`;
        }
    } else {
        img_html = ``;
    }

    if (vid1.length > 0) {
        vid_html = `<div class="video1">
                        <video controls="" src="`+ vid1 + `"></video>
                    </div>`;
    }

    // カスタム絵文字を非同期に差し替え
    contentHtml = await replaceMentions(contentHtml);
    contentHtml = await replaceCustomEmojis(contentHtml);

    if (ueuse["type"] == "Reuse") {
        if (ueuse["ueuse"].length > 0) {
            if (YouTube_and_nicovideo_Links(ueuse["ueuse"])) {
                contentHtml = contentHtml + YouTube_and_nicovideo_Links(ueuse["ueuse"]);
            }
        } else {
            if (YouTube_and_nicovideo_Links(ueuse["reuse"]["ueuse"])) {
                contentHtml = contentHtml + YouTube_and_nicovideo_Links(ueuse["reuse"]["ueuse"]);
            }
        }

    } else {
        if (YouTube_and_nicovideo_Links(ueuse["ueuse"])) {
            contentHtml = contentHtml + YouTube_and_nicovideo_Links(ueuse["ueuse"]);
        }
    }
    var favbox = `
        <hr>
        <div class="favbox">
            <button class="`+ is_fav["class"] + `" id="favbtn" data-uniqid="` + uniqid + `" data-userid2="` + userid + `"><svg><use xlink:href="` + is_fav["icon"] + `" alt="いいね"></use></svg><span class="like-count">` + favoritecount + `</span></button>
            <button name="reusebtn" id="reusebtn" class="`+ is_reu["class"] + `" data-uniqid="` + ueuse["uniqid"] + `" data-userid="` + userid + `"><svg><use xlink:href="../img/sysimage/reuse_1.svg#reuse_1"></use></svg><span class="like-count">` + reusecount + `</span></button>
            <a href="/!`+ uniqid + `" class="tuduki"><svg><use xlink:href="../img/sysimage/reply_1.svg#reply_1"></use></svg>` + replycount + `</a>
            
            <button name="bookmark" id="bookmark" class="`+ is_bok["class"] + `" data-uniqid="` + uniqid + `" data-userid="` + userid + `"><svg><use xlink:href="../img/sysimage/bookmark_1.svg#bookmark_1"></use></svg></button>
            `+ addabi + `
            <button name="popup" id="popup" class="etcbtn" data-uniqid="`+ uniqid + `" data-userid="` + userid + `"><svg><use xlink:href="../img/sysimage/etc_1.svg#etc_1"></use></svg></button>
        </div>
        `

    if (ueuse["is_activitypub"] == true) {
        favbox = "";
    }

    html = `
        <div class="ueuse" id="ueuse-`+ ueuse["uniqid"] + `">
            `+ reuse + `
            <div class="flebox">
                <a href="/@`+ userid + `"><img src="` + iconurl + `"></a>
                <a href="/@`+ userid + `"><div class="u_name">` + await replaceCustomEmojis(username) + `</div></a>
                <div class="idbox">
                    <a href="/@`+ userid + `">@` + userid + `</a>
                </div>
                `+ bot + `
                `+ check + `
                <div class="time">`+ formatSmartDate(datetime) + `</div>
            </div>
            `+ nsfw_html + `
            `+ nsfw_start_html + `
            <div class="content">`+ contentHtml + `</div>
            `+ img_html + `
            `+ vid_html + `
            `+ inyo + `
            `+ abi_html + `
            `+ nsfw_end_html + `
            `+ favbox + `
        </div>
    `;
    return html;
}
function createAdsHtml(ads) {
    if (!(ads == null || ads == "")) {
        var ads_html = `<div class="ads">
                            <a href="`+ ads["url"] + `" target="_blank">
                                <img src="`+ ads["imgurl"] + `" title="` + ads["memo"] + `">
                            </a>
                        </div>`;
        return ads_html;
    } else {
        var ads_html = ``;
        return ads_html;
    }
}

// 投稿一覧を非同期で全部HTML化 → そのあと順番通りにappend
async function renderUeuses(ueuseData, selectedUniqid = null) {
    if (ueuseData["success"] == false) {
        var errmsg;
        if (ueuseData["error"] == "no_ueuse") {
            errmsg = "ユーズがありません";
        } else if (ueuseData["error"] == "bad_request") {
            errmsg = "不正なリクエストが検出されました";
        }
        $("#postContainer").append(`<div class="tokonone" id="noueuse"><p>` + errmsg + `</p></div>`);
        return true;
    } else {
        var htmlList = [];
        var ueuseList = ueuseData["ueuses"];
        for (const ueuse of ueuseList) {
            const html = await createUeuseHtml(ueuse, selectedUniqid);
            htmlList.push(html);
        }

        var ads = ueuseData["ads"];
        const ads_html = createAdsHtml(ads);
        htmlList.push(ads_html);

        // 投稿順を保ったままDOMへ追加
        for (const html of htmlList) {
            $("#postContainer").append(html);
        }
        return true;
    }
}


async function createNotificationHtml(notification) {
    let html = "";
    let is_readclass = "";
    let datetime = notification["datetime"];
    let userid = notification["userdata"]["userid"];
    let username = notification["userdata"]["username"];
    let iconurl = notification["userdata"]["iconurl"];
    let title = notification["title"];
    let content = formatMarkdown(a_link(notification["message"]));
    content = await replaceMentions(content);
    content = await replaceCustomEmojis(content);

    let url = notification["url"];

    if(notification["is_read"] == false) {
        is_readclass = "this";
    }

    html = `
        <div class="notification `+is_readclass+`">
            <div class="flebox">
                <div class="time">`+formatSmartDate(datetime)+`</div>
            </div>
            <div class="flebox">
                <div class="icon">
                    <a href="/@`+userid+`">
                        <img src="`+iconurl+`">
                    </a>
                </div>
                <div class="username">
                    <a href="/@`+userid+`">`+await replaceCustomEmojis(username)+`</a>
                </div>
            </div>
            <h3>`+await replaceCustomEmojis(title)+`</h3>
            <p>`+content+`</p>
            <a href="`+url+`">詳細をみる</a>
        </div>
    `;
    return html;
}

async function renderNotifications(notificationData) {
    if (notificationData["success"] == false) {
        var errmsg;
        if (notificationData["error"] == "no_notification") {
            errmsg = "通知がありません";
        } else if (notificationData["error"] == "bad_request") {
            errmsg = "不正なリクエストが検出されました";
        }
        $("#postContainer").append(`<div class="tokonone" id="noueuse"><p>` + errmsg + `</p></div>`);
        return true;
    } else {
        var htmlList = [];
        var notificationList = notificationData["notifications"];

        for (const notification of notificationList) {
            const html = await createNotificationHtml(notification);
            htmlList.push(html);
        }

        // 投稿順を保ったままDOMへ追加
        for (const html of htmlList) {
            $("#postContainer").append(html);
        }
        return true;
    }
}