import { attachContextMenu } from "preact-context-menu";
import { memo } from "preact/compat";
import { useContext } from "preact/hooks";

import { QueuedMessage } from "../../../redux/reducers/queue";

import { useIntermediate } from "../../../context/intermediate/Intermediate";
import { AppContext } from "../../../context/revoltjs/RevoltClient";
import { useUser } from "../../../context/revoltjs/hooks";
import { MessageObject } from "../../../context/revoltjs/util";

import Overline from "../../ui/Overline";

import { Children } from "../../../types/Preact";
import Markdown from "../../markdown/Markdown";
import UserIcon from "../user/UserIcon";
import { Username } from "../user/UserShort";
import MessageBase, {
    MessageContent,
    MessageDetail,
    MessageInfo,
} from "./MessageBase";
import Attachment from "./attachments/Attachment";
import { MessageReply } from "./attachments/MessageReply";
import Embed from "./embed/Embed";

interface Props {
    attachContext?: boolean;
    queued?: QueuedMessage;
    message: MessageObject;
    contrast?: boolean;
    content?: Children;
    head?: boolean;
}

function Message({
    attachContext,
    message,
    contrast,
    content: replacement,
    head: preferHead,
    queued,
}: Props) {
    // TODO: Can improve re-renders here by providing a list
    // TODO: of dependencies. We only need to update on u/avatar.
    const user = useUser(message.author);
    const client = useContext(AppContext);
    const { openScreen } = useIntermediate();

    const content = message.content as string;
    const head = preferHead || (message.replies && message.replies.length > 0);

    // ! FIXME: tell fatal to make this type generic
    // bree: Fatal please...
    const userContext = attachContext
        ? (attachContextMenu("Menu", {
              user: message.author,
              contextualChannel: message.channel,
          }) as any)
        : undefined;

    const openProfile = () =>
        openScreen({ id: "profile", user_id: message.author });

    return (
        <div id={message._id}>
            {message.replies?.map((message_id, index) => (
                <MessageReply
                    index={index}
                    id={message_id}
                    channel={message.channel}
                />
            ))}
            <MessageBase
                head={head && !(message.replies && message.replies.length > 0)}
                contrast={contrast}
                sending={typeof queued !== "undefined"}
                mention={message.mentions?.includes(client.user!._id)}
                failed={typeof queued?.error !== "undefined"}
                onContextMenu={
                    attachContext
                        ? attachContextMenu("Menu", {
                              message,
                              contextualChannel: message.channel,
                              queued,
                          })
                        : undefined
                }>
                <MessageInfo>
                    {head ? (
                        <UserIcon
                            target={user}
                            size={36}
                            onContextMenu={userContext}
                            onClick={openProfile}
                        />
                    ) : (
                        <MessageDetail message={message} position="left" />
                    )}
                </MessageInfo>
                <MessageContent>
                    {head && (
                        <span className="detail">
                            <Username
                                className="author"
                                user={user}
                                onContextMenu={userContext}
                                onClick={openProfile}
                            />
                            <MessageDetail message={message} position="top" />
                        </span>
                    )}
                    {replacement ?? <Markdown content={content} />}
                    {queued?.error && (
                        <Overline type="error" error={queued.error} />
                    )}
                    {message.attachments?.map((attachment, index) => (
                        <Attachment
                            key={index}
                            attachment={attachment}
                            hasContent={index > 0 || content.length > 0}
                        />
                    ))}
                    {message.embeds?.map((embed, index) => (
                        <Embed key={index} embed={embed} />
                    ))}
                </MessageContent>
            </MessageBase>
        </div>
    );
}

export default memo(Message);