"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatBox = ChatBox;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const graphemer_1 = tslib_1.__importDefault(require("graphemer"));
const lucide_react_native_1 = require("lucide-react-native");
const process_1 = require("process");
const react_1 = require("react");
const react_native_1 = require("react-native");
const __1 = require("../../");
const slash_commands_1 = require("../../lib/slash-commands");
const teleport_1 = require("../../lib/slash-commands/teleport");
const stream_notifications_1 = require("../../lib/stream-notifications");
const system_messages_1 = require("../../lib/system-messages");
const atoms_1 = require("../../lib/theme/atoms");
const livestream_store_1 = require("../../livestream-store");
const streamplace_store_1 = require("../../streamplace-store");
const textarea_1 = require("../ui/textarea");
const chat_message_1 = require("./chat-message");
const emoji_suggestions_1 = require("./emoji-suggestions");
const mention_suggestions_1 = require("./mention-suggestions");
const teleport_modal_1 = require("./teleport-modal");
const COOL_EMOJI_LIST = [
    // @ts-ignore we can iterate through this just fine it seems
    ..."😀🥸😍😘😁🥸😆🥸😜🥸😂😅🥸🙂🤫😱🥸🤣😗😄🥸😎🤓😲😯😰🥸😥🥸😣🥸😞😓🥸😩😩🥸😤🥱",
];
const graphemer = new graphemer_1.default();
function ChatBox({ isPopout, chatBoxStyle, emojiData, setIsChatVisible, onEmojiPickerToggle, emojiPicker, skinTone = 0, hideLogin = false, leftSlot, }) {
    const [submitting, setSubmitting] = (0, react_1.useState)(false);
    const [inputFocused, setInputFocused] = (0, react_1.useState)(false);
    const message = (0, livestream_store_1.useChatDraft)();
    const setMessage = (0, livestream_store_1.useSetChatDraft)();
    const [showSuggestions, setShowSuggestions] = (0, react_1.useState)(false);
    const [showEmojiSuggestions, setShowEmojiSuggestions] = (0, react_1.useState)(false);
    const [showEmojiSelector, setShowEmojiSelector] = (0, react_1.useState)(false);
    const [emojiIconIndex, setEmojiIconIndex] = (0, react_1.useState)(Math.floor(Math.random() * COOL_EMOJI_LIST.length));
    const [highlightedIndex, setHighlightedIndex] = (0, react_1.useState)(0);
    const [filteredAuthors, setFilteredAuthors] = (0, react_1.useState)(new Map());
    const [filteredEmojis, setFilteredEmojis] = (0, react_1.useState)([]);
    const [showTeleportModal, setShowTeleportModal] = (0, react_1.useState)(false);
    const isOverLimit = graphemer.countGraphemes(message) > 300;
    let linfo = (0, livestream_store_1.useLivestream)();
    const profile = (0, livestream_store_1.useProfile)();
    const { theme, zero: zt } = (0, __1.useTheme)();
    const chat = (0, livestream_store_1.useChat)();
    const createChatMessage = (0, livestream_store_1.useCreateChatMessage)();
    const addSystemMessage = (0, livestream_store_1.useAddSystemMessage)();
    const replyTo = (0, livestream_store_1.useReplyToMessage)();
    const setReplyToMessage = (0, livestream_store_1.useSetReplyToMessage)();
    const textAreaRef = (0, react_1.useRef)(null);
    const pdsAgent = (0, streamplace_store_1.usePDSAgent)();
    const userDID = (0, streamplace_store_1.useDID)();
    const setActiveTeleportUri = (0, livestream_store_1.useLivestreamStore)((state) => state.setActiveTeleportUri);
    (0, react_1.useEffect)(() => {
        if (pdsAgent && userDID) {
            (0, teleport_1.registerTeleportCommand)(pdsAgent, userDID, setActiveTeleportUri, () => setShowTeleportModal(true));
        }
    }, [pdsAgent, userDID, setActiveTeleportUri]);
    const authors = (0, react_1.useMemo)(() => {
        if (!chat)
            return null;
        return chat.reduce((acc, msg) => {
            // our fake system user "did"
            if (msg.author.did === "did:sys:system")
                return acc;
            if (acc.has(msg.author.handle))
                return acc;
            acc.set(msg.author.handle, msg.chatProfile);
            return acc;
        }, new Map());
    }, [chat]);
    (0, react_1.useEffect)(() => {
        if (pdsAgent && linfo?.author?.did && pdsAgent.did === linfo.author.did) {
            (0, teleport_1.registerTeleportCommand)(pdsAgent, pdsAgent.did, setActiveTeleportUri, () => setShowTeleportModal(true));
        }
    }, [pdsAgent, linfo?.author?.did, setActiveTeleportUri]);
    const handleMentionSelect = (handle) => {
        const beforeAt = message.slice(0, message.lastIndexOf("@"));
        setMessage(`${beforeAt}@${handle} `);
        setShowSuggestions(false);
    };
    const handleEmojiSelect = (emoji) => {
        console.log("[ChatBox] handleEmojiSelect", emoji);
        if (emoji.s) {
            const beforeColon = message.slice(0, message.lastIndexOf(":"));
            setMessage(`${beforeColon}${(0, emoji_suggestions_1.getSkinNative)(emoji, skinTone)} `);
        }
        else if (emoji.type === "standard") {
            setMessage(message + emoji.native);
        }
        else if (emoji.type === "custom") {
            setMessage(message + `:${emoji.name}: `);
        }
        setShowEmojiSuggestions(false);
    };
    const handleTeleportSubmit = async (targetHandle, countdownSeconds) => {
        if (!pdsAgent || !userDID)
            return;
        const result = await (0, teleport_1.createTeleport)(pdsAgent, userDID, targetHandle, countdownSeconds, setActiveTeleportUri);
        if (!result.success && result.error) {
            system_messages_1.SystemMessages.commandError(result.error);
        }
    };
    const updateSuggestions = (text) => {
        // Handle mentions
        const atIndex = text.lastIndexOf("@");
        if (atIndex !== -1 && authors) {
            const searchText = text.slice(atIndex + 1).toLowerCase();
            const filteredAuthorsMap = new Map(Array.from(authors.entries()).filter(([handle]) => handle.toLowerCase().includes(searchText)));
            setFilteredAuthors(filteredAuthorsMap);
            setHighlightedIndex(0);
            setShowSuggestions(filteredAuthorsMap.size > 0);
            setShowEmojiSuggestions(false);
        }
        else {
            setShowSuggestions(false);
        }
        const colonIndex = text.lastIndexOf(":");
        if (colonIndex !== -1) {
            const searchText = text.slice(colonIndex + 1).toLowerCase();
            if (searchText.length >= 3 && !searchText.includes(" ")) {
                if (!emojiData)
                    return;
                const aliasMatches = Object.entries(emojiData.aliases)
                    .map(([alias, emojiId]) => {
                    const aliasLower = alias.toLowerCase();
                    if (aliasLower === searchText) {
                        return { emojiId, alias, matchType: 0, index: 0 };
                    }
                    else if (aliasLower.startsWith(searchText)) {
                        return { emojiId, alias, matchType: 1, index: 0 };
                    }
                    else if (aliasLower.includes(searchText)) {
                        return {
                            emojiId,
                            alias,
                            matchType: 2,
                            index: aliasLower.indexOf(searchText),
                        }; // includes
                    }
                    return null;
                })
                    .filter(Boolean);
                // Map emojiId to best alias match info
                const bestAliasMatch = {};
                for (const match of aliasMatches) {
                    if (!match)
                        continue;
                    const prev = bestAliasMatch[match.emojiId];
                    if (!prev ||
                        match?.matchType < prev.matchType ||
                        (match.matchType === prev.matchType && match.index < prev.index)) {
                        bestAliasMatch[match.emojiId] = match;
                    }
                }
                // Collect all matching emojis by id, name, keywords, or alias
                const allEmojis = Object.values(emojiData.emojis);
                const filtered = allEmojis
                    .map((emoji) => {
                    // Check alias match
                    const aliasMatch = bestAliasMatch[emoji.id];
                    if (aliasMatch) {
                        return {
                            emoji,
                            sort: [aliasMatch.matchType, aliasMatch.index, 0],
                        };
                    }
                    // Check id, name, keywords
                    if (emoji.id.toLowerCase() === searchText) {
                        return { emoji, sort: [3, 0, 0] }; // exact id
                    }
                    if (emoji.id.toLowerCase().startsWith(searchText)) {
                        return { emoji, sort: [4, 0, 0] }; // startsWith id
                    }
                    if (emoji.id.toLowerCase().includes(searchText)) {
                        return {
                            emoji,
                            sort: [5, emoji.id.toLowerCase().indexOf(searchText), 0],
                        }; // includes id
                    }
                    if (emoji.m.toLowerCase().includes(searchText)) {
                        return {
                            emoji,
                            sort: [6, emoji.m.toLowerCase().indexOf(searchText), 0],
                        };
                    }
                    if (emoji.k &&
                        emoji.k.some((keyword) => keyword.toLowerCase().includes(searchText))) {
                        return { emoji, sort: [7, 0, 0] };
                    }
                    return null;
                })
                    .filter(Boolean)
                    // Remove duplicates by emoji id (keep best match)
                    .reduce((acc, curr) => {
                    if (!acc.find((e) => e.emoji.id === curr.emoji.id)) {
                        acc.push(curr);
                    }
                    return acc;
                }, [])
                    // Sort by alias match type, then position, then fallback
                    .sort((a, b) => {
                    for (let i = 0; i < a.sort.length; ++i) {
                        if (a.sort[i] !== b.sort[i])
                            return a.sort[i] - b.sort[i];
                    }
                    return 0;
                })
                    .slice(0, 10) // Limit to 10 results
                    .map((entry) => entry.emoji);
                setFilteredEmojis(filtered);
                setHighlightedIndex(0);
                setShowEmojiSuggestions(filtered.length > 0);
                setShowSuggestions(false);
            }
            else {
                setShowEmojiSuggestions(false);
            }
        }
        else {
            setShowEmojiSuggestions(false);
        }
        // If neither mention nor emoji, hide all suggestions
        if (atIndex === -1 && colonIndex === -1) {
            setShowSuggestions(false);
            setShowEmojiSuggestions(false);
        }
    };
    const submit = async () => {
        if (!message.trim())
            return;
        if (graphemer.countGraphemes(message) > 300) {
            __1.toast.show("Message too long", "Please limit your message to 300 characters.", {
                variant: "error",
                duration: 3,
            });
            return;
        }
        const messageText = message;
        setMessage("");
        setReplyToMessage(null);
        if (messageText.startsWith("/")) {
            const result = await (0, slash_commands_1.handleSlashCommand)(messageText);
            if (result.handled) {
                if (result.error) {
                    console.error("Slash command error:", result.error);
                    addSystemMessage(system_messages_1.SystemMessages.commandError(result.error));
                }
                return;
            }
        }
        setSubmitting(true);
        try {
            const result = await (0, slash_commands_1.handleSlashCommand)(messageText);
            if (result.handled) {
                if (result.error) {
                    console.error("Slash command error:", result.error);
                }
            }
            else {
                await createChatMessage({
                    text: messageText,
                    reply: replyTo || undefined,
                });
            }
        }
        catch (err) {
            console.error("Error submitting message:", err);
            __1.toast.show("Failed to send message", "Please try again.", {
                variant: "error",
                duration: 3,
            });
        }
        finally {
            setSubmitting(false);
        }
        if (textAreaRef.current && !textAreaRef.current.isFocused()) {
            textAreaRef.current.focus();
            requestAnimationFrame(() => {
                textAreaRef.current?.focus();
            });
        }
    };
    (0, react_1.useEffect)(() => {
        if (replyTo && textAreaRef.current) {
            textAreaRef.current.focus();
        }
    }, [replyTo]);
    return ((0, jsx_runtime_1.jsxs)(__1.View, { style: [atoms_1.layout.flex.column, atoms_1.flex.shrink[1], atoms_1.gap.all[2]], children: [(0, jsx_runtime_1.jsx)(teleport_modal_1.TeleportModal, { open: showTeleportModal, onOpenChange: setShowTeleportModal, onSubmit: handleTeleportSubmit }), replyTo && ((0, jsx_runtime_1.jsxs)(__1.View, { style: [
                    atoms_1.layout.flex.row,
                    atoms_1.layout.flex.alignCenter,
                    atoms_1.layout.flex.spaceBetween,
                    atoms_1.pl[2],
                    atoms_1.pr[1],
                    atoms_1.mb[2],
                    atoms_1.py[1],
                    atoms_1.r["2xl"],
                    zt.bg.card,
                ], children: [(0, jsx_runtime_1.jsx)(__1.View, { style: { flex: 1, minWidth: 0, marginRight: 8 }, children: (0, jsx_runtime_1.jsx)(chat_message_1.RenderChatMessage, { item: replyTo, showReply: false, userCache: authors || new Map() }) }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => setReplyToMessage(null), style: [
                            atoms_1.layout.flex.row,
                            atoms_1.layout.flex.alignCenter,
                            atoms_1.layout.flex.justifyCenter,
                            atoms_1.h[8],
                            atoms_1.w[8],
                            zt.bg.muted,
                            zt.border.border,
                            atoms_1.borders.width.thin,
                            { borderRadius: 999 },
                        ], children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.X, { size: 24, style: [zt.text.primaryForeground] }) })] })), (0, jsx_runtime_1.jsxs)(__1.View, { style: [atoms_1.layout.flex.row, atoms_1.layout.flex.alignCenter, atoms_1.gap.all[2]], children: [(0, jsx_runtime_1.jsxs)(__1.View, { style: leftSlot
                            ? [
                                atoms_1.layout.flex.row,
                                atoms_1.layout.flex.alignCenter,
                                { flex: 1 },
                                atoms_1.borders.width.thin,
                                atoms_1.borders.color.gray[400],
                                atoms_1.bg.gray[900],
                                chatBoxStyle,
                                isOverLimit
                                    ? {
                                        borderColor: "#ef4444",
                                        borderWidth: 2,
                                        outline: "none",
                                    }
                                    : inputFocused
                                        ? {
                                            borderColor: theme.colors.foreground,
                                            outline: "none",
                                        }
                                        : null,
                                atoms_1.pr[2],
                            ]
                            : [{ flex: 1 }], children: [leftSlot, (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { ref: textAreaRef, numberOfLines: 1, value: message, enterKeyHint: "send", onSubmitEditing: (e) => {
                                    e.preventDefault();
                                    submit();
                                }, multiline: false, onChangeText: (text) => {
                                    setMessage(text);
                                    updateSuggestions(text);
                                }, onKeyPress: (k) => {
                                    if (k.nativeEvent.key === "Enter") {
                                        if (showSuggestions) {
                                            k.preventDefault();
                                            const handles = Array.from(filteredAuthors.keys());
                                            if (handles.length > 0) {
                                                handleMentionSelect(handles[highlightedIndex]);
                                            }
                                        }
                                        else if (showEmojiSuggestions) {
                                            k.preventDefault();
                                            if (filteredEmojis.length > 0) {
                                                handleEmojiSelect(filteredEmojis[highlightedIndex]);
                                            }
                                        }
                                        else {
                                            k.preventDefault();
                                            submit();
                                        }
                                    }
                                    else if (k.nativeEvent.key === "Tab") {
                                        if (showSuggestions) {
                                            k.preventDefault();
                                            const handles = Array.from(filteredAuthors.keys());
                                            if (handles.length > 0) {
                                                handleMentionSelect(handles[highlightedIndex]);
                                            }
                                        }
                                        else if (showEmojiSuggestions) {
                                            k.preventDefault();
                                            if (filteredEmojis.length > 0) {
                                                handleEmojiSelect(filteredEmojis[highlightedIndex]);
                                            }
                                        }
                                    }
                                    else if (k.nativeEvent.key === "ArrowUp") {
                                        if (showSuggestions || showEmojiSuggestions) {
                                            k.preventDefault();
                                            setHighlightedIndex((prev) => Math.max(prev - 1, 0));
                                        }
                                    }
                                    else if (k.nativeEvent.key === "ArrowDown") {
                                        if (showSuggestions) {
                                            k.preventDefault();
                                            setHighlightedIndex((prev) => Math.min(prev + 1, Array.from(filteredAuthors.keys()).length - 1));
                                        }
                                        else if (showEmojiSuggestions) {
                                            k.preventDefault();
                                            setHighlightedIndex((prev) => Math.min(prev + 1, filteredEmojis.length - 1));
                                        }
                                    }
                                    else if (k.nativeEvent.key === "Escape") {
                                        if (showSuggestions || showEmojiSuggestions) {
                                            k.preventDefault();
                                            setShowSuggestions(false);
                                            setShowEmojiSuggestions(false);
                                        }
                                        else if (replyTo) {
                                            k.preventDefault();
                                            setReplyToMessage(null);
                                        }
                                    }
                                }, onFocus: () => setInputFocused(true), onBlur: () => setInputFocused(false), style: leftSlot
                                    ? [
                                        {
                                            flex: 1,
                                            borderWidth: 0,
                                            backgroundColor: "transparent",
                                            outline: "none",
                                        },
                                    ]
                                    : [
                                        chatBoxStyle,
                                        isOverLimit && {
                                            borderColor: "#ef4444",
                                            borderWidth: 2,
                                            outline: "none",
                                        },
                                    ], 
                                // "submit" won't blur on enter
                                submitBehavior: "submit", placeholder: "Type a message..." })] }), (0, jsx_runtime_1.jsx)(__1.View, { children: (0, jsx_runtime_1.jsx)(__1.Button, { disabled: submitting, variant: "secondary", width: "min", style: { borderRadius: 16, height: 43 }, onPress: submit, children: submitting ? (0, jsx_runtime_1.jsx)(__1.Loader, {}) : "Send" }) })] }), showSuggestions && ((0, jsx_runtime_1.jsx)(mention_suggestions_1.MentionSuggestions, { authors: filteredAuthors || new Map(), highlightedIndex: highlightedIndex, onSelect: handleMentionSelect })), showEmojiSuggestions && ((0, jsx_runtime_1.jsx)(emoji_suggestions_1.EmojiSuggestions, { emojis: filteredEmojis, highlightedIndex: highlightedIndex, onSelect: handleEmojiSelect, skinTone: skinTone })), react_native_1.Platform.OS === "web" && ((0, jsx_runtime_1.jsxs)(__1.View, { style: [
                    atoms_1.layout.flex.row,
                    atoms_1.mb[2],
                    atoms_1.gap.all[2],
                    { justifyContent: "flex-end", position: "relative" },
                ], children: [emojiPicker?.(showEmojiSelector, () => setShowEmojiSelector(false), handleEmojiSelect), process_1.env.NODE_ENV === "development" && ((0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16 }, width: "min", onPress: () => {
                            stream_notifications_1.StreamNotifications.teleport({
                                targetHandle: "test.bsky.social",
                                targetDID: "did:plc:test",
                                countdown: 30,
                                canCancel: true,
                                onDismiss: (reason) => console.log("teleport dismissed:", reason),
                            });
                        }, children: "Test Notification" })), (0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, maxWidth: 44, aspectRatio: 1 }, "aria-label": "Insert Mention", onPress: () => {
                            !message.endsWith("@") && setMessage(message + "@");
                            const atIndex = message.lastIndexOf("@");
                            const searchText = message.slice(atIndex + 1).toLowerCase();
                            updateSuggestions(searchText);
                            setShowSuggestions(true);
                            textAreaRef.current?.focus();
                        }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.AtSignIcon, { size: 20, color: "white" }) }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onHoverOut: () => {
                            setEmojiIconIndex(Math.floor(Math.random() * COOL_EMOJI_LIST.length));
                        }, children: (0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", id: "web-emoji-picker-btn", "aria-label": "Insert Emoji", style: { borderRadius: 16, maxWidth: 44, aspectRatio: 1 }, onPress: () => {
                                onEmojiPickerToggle
                                    ? onEmojiPickerToggle()
                                    : setShowEmojiSelector(!showEmojiSelector);
                            }, children: (0, jsx_runtime_1.jsx)(__1.Text, { children: COOL_EMOJI_LIST[emojiIconIndex] }) }) }), !isPopout && ((0, jsx_runtime_1.jsx)(__1.Button
                    // @ts-ignore this should work fine on web and get ignored on mobile
                    , { 
                        // @ts-ignore this should work fine on web and get ignored on mobile
                        href: `/chat-popout/${linfo?.author?.did}`, variant: "secondary", "aria-label": "Popout Chat", style: { borderRadius: 16, maxWidth: 44, aspectRatio: 1 }, onPress: () => {
                            const did = linfo?.author?.did ?? profile?.did;
                            if (did) {
                                const u = new URL(window.location.href);
                                u.pathname = `/chat-popout/${did}`;
                                window.open(u.toString(), "_blank", "popup=true,width=480,height=600");
                            }
                            setIsChatVisible?.(false);
                        }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.ExternalLink, { color: theme.colors.primaryForeground, size: 16 }) }))] }))] }));
}
//# sourceMappingURL=chat-box.js.map