import { emojiRegex } from "./emoji-regex.js";
import { fetchMeta } from "./fetch-meta.js";
import { Emojis, UserEmojis, UserGroups, Users } from "../models/index.js";
import { toPunyNullable } from "./convert-host.js";
import { IsNull } from "typeorm";
import { resolveUser } from "../remote/resolve-user.js";
const legacies = new Map([
    [
        "like",
        "👍"
    ],
    [
        "love",
        "❤️"
    ],
    [
        "laugh",
        "😆"
    ],
    [
        "hmm",
        "🤔"
    ],
    [
        "surprise",
        "😮"
    ],
    [
        "congrats",
        "🎉"
    ],
    [
        "angry",
        "💢"
    ],
    [
        "confused",
        "😥"
    ],
    [
        "rip",
        "😇"
    ],
    [
        "pudding",
        "🍮"
    ],
    [
        "star",
        "⭐"
    ]
]);
export async function getFallbackReaction() {
    const meta = await fetchMeta();
    return meta.defaultReaction;
}
export function convertLegacyReactions(reactions) {
    const _reactions = new Map();
    const decodedReactions = new Map();
    for(const reaction in reactions){
        if (reactions[reaction] <= 0) continue;
        let decodedReaction;
        if (decodedReactions.has(reaction)) {
            decodedReaction = decodedReactions.get(reaction);
        } else {
            decodedReaction = decodeReaction(reaction);
            decodedReactions.set(reaction, decodedReaction);
        }
        let emoji = legacies.get(decodedReaction.reaction);
        if (emoji) {
            _reactions.set(emoji, (_reactions.get(emoji) || 0) + reactions[reaction]);
        } else {
            _reactions.set(reaction, (_reactions.get(reaction) || 0) + reactions[reaction]);
        }
    }
    const _reactions2 = new Map();
    for (const [reaction, count] of _reactions){
        const decodedReaction = decodedReactions.get(reaction);
        _reactions2.set(decodedReaction.reaction, count);
    }
    return Object.fromEntries(_reactions2);
}
export async function toDbReaction(reaction, reacterHost, recurse = true) {
    if (!reaction) return await getFallbackReaction();
    reacterHost = toPunyNullable(reacterHost);
    // Convert string-type reactions to unicode
    const emoji = legacies.get(reaction) || (reaction === "♥️" ? "❤️" : null);
    if (emoji) return emoji;
    // Allow unicode reactions
    const match = emojiRegex.exec(reaction);
    if (match) {
        const unicode = match[0];
        return unicode;
    }
    const custom = reaction.match(/^:([^:\s]+):$/);
    if (custom) {
        const decoded = decodeReaction(reaction);
        if (decoded.name) {
            const groupCustom = decoded.name.match(/^([a-z0-9_]{1,64})@@([a-zA-Z0-9_]{1,64})$/);
            if (groupCustom) {
                const group = await UserGroups.findOneBy({
                    username: groupCustom[2].toLowerCase()
                });
                const groupEmoji = group ? await UserEmojis.findOneBy({
                    name: groupCustom[1],
                    userGroupId: group.id,
                    glyph: false
                }) : null;
                if (groupEmoji) return `:${groupCustom[1]}@@${group.username}:`;
            }
            const emoji = await Emojis.findOneBy({
                host: decoded.host ?? reacterHost ?? IsNull(),
                name: decoded.name
            });
            if (emoji) return emoji.host ? `:${emoji.name}@${emoji.host}:` : `:${emoji.name}:`;
        }
        if (await isUserReaction(reaction)) return reaction;
    }
    return recurse && reacterHost == null && reaction !== null ? await toDbReaction(`:${reaction}:`, reacterHost, false) : await getFallbackReaction();
}
export function decodeReaction(str) {
    const custom = str.match(/^:([^:\s]+):$/);
    if (custom) {
        const body = custom[1];
        const parts = body.split("@");
        const name = parts[0];
        const host = parts.length === 2 ? parts[1] || null : null;
        return {
            reaction: host ? `:${name}@${host}:` : str,
            name,
            host
        };
    }
    return {
        reaction: str,
        name: undefined,
        host: undefined
    };
}
async function isUserReaction(reaction) {
    const body = reaction.slice(1, -1);
    const icon = body.match(/^@([^@:\s]+)(?:@([^@:\s]+))?$/);
    if (icon) {
        return await findUser(icon[1], icon[2] ?? null) != null;
    }
    if (/^@@[a-zA-Z0-9_]{1,64}$/.test(body)) return false;
    const groupCustom = body.match(/^([a-z0-9_]{1,64})@@([a-zA-Z0-9_]{1,64})$/);
    if (groupCustom) {
        const group = await UserGroups.findOneBy({
            username: groupCustom[2].toLowerCase()
        });
        if (!group) return false;
        return await UserEmojis.findOneBy({
            name: groupCustom[1],
            userGroupId: group.id,
            glyph: false
        }) != null;
    }
    const parts = body.split("@");
    if (parts.length !== 2 && parts.length !== 3) return false;
    const [name, username, host] = parts;
    if (!name || !username) return false;
    const user = await findUser(username, host ?? null);
    if (!user) return false;
    return await UserEmojis.findOneBy({
        name,
        userId: user.id
    }) != null;
}
async function findUser(username, host) {
    const normalizedHost = toPunyNullable(host);
    const user = await Users.findOneBy({
        usernameLower: username.toLowerCase(),
        host: normalizedHost ?? IsNull()
    });
    if (user) return user;
    if (normalizedHost == null) return null;
    return resolveUser(username, normalizedHost).catch(()=>null);
}
export function convertLegacyReaction(reaction) {
    const decoded = decodeReaction(reaction).reaction;
    if (legacies.has(decoded)) return legacies.get(decoded);
    return decoded;
}
