import {
    useInfiniteQuery,
    type QueryFunctionContext,
} from "@tanstack/react-query";
import type { Channel, Message, MessageId } from "~/lib/api/types";
import ChatMessage from "./chat-message";
import MessageBox from "./message-box";
import { Separator } from "./ui/separator";
import VisibleTrigger from "./visible-trigger";

interface ChannelAreaProps {
    channel: Channel;
}

export default function ChannelArea({ channel }: ChannelAreaProps) {
    const channelId = channel.id;

    const fetchMessages = async ({ pageParam }: QueryFunctionContext) => {
        return await import("~/lib/api/client/channel").then((m) =>
            m.default.paginatedMessages(
                channelId,
                50,
                pageParam as MessageId | undefined,
            ),
        );
    };

    const {
        data,
        error,
        fetchNextPage,
        hasNextPage,
        isFetching,
        isFetchingNextPage,
        isPending,
        status,
    } = useInfiniteQuery({
        queryKey: ["messages", channelId],
        initialPageParam: undefined,
        queryFn: fetchMessages,
        getNextPageParam: (lastPage) =>
            lastPage.length < 50
                ? undefined
                : lastPage[lastPage.length - 1]?.id,
        staleTime: Infinity,
    });

    const fetchNextPageVisible = () => {
        if (!isFetchingNextPage && hasNextPage) fetchNextPage();
    };

    let messageArea = null;

    if (isPending) {
        messageArea = (
            <div className="flex items-center justify-center size-full">
                <span>Loading...</span>
            </div>
        );
    } else {
        messageArea = (
            <>
                <div className="flex-1" />
                <div className="flex flex-col-reverse overflow-auto gap-2 pb-2 pr-2">
                    {status === "success" && renderMessages(data.pages)}
                    <VisibleTrigger
                        triggerOnce={false}
                        onVisible={fetchNextPageVisible}
                    />
                </div>
            </>
        );
    }

    return (
        <>
            <div className="flex flex-col size-full">
                <div className="w-full min-h-12 border-b-2 flex items-center justify-center">
                    {channel?.name}
                </div>
                <div className="flex-1 overflow-y-auto flex flex-col pl-2 pr-0.5">
                    {messageArea}
                </div>
                <div className="w-full">
                    <MessageBox channelId={channelId} />
                </div>
            </div>
        </>
    );
}

function renderMessages(pages: Message[][]) {
    const messageElements: React.ReactNode[] = [];
    let lastDate: string | null = null;

    const formatMessageDate = (date: Date) => {
        const now = new Date();
        const today = new Date(
            now.getFullYear(),
            now.getMonth(),
            now.getDate(),
        );
        const yesterday = new Date(today);
        yesterday.setDate(yesterday.getDate() - 1);

        const messageDate = new Date(
            date.getFullYear(),
            date.getMonth(),
            date.getDate(),
        );

        const capitalize = (str: string) =>
            str.charAt(0).toUpperCase() + str.slice(1);

        if (messageDate.getTime() === today.getTime()) {
            const rtf = new Intl.RelativeTimeFormat(undefined, {
                numeric: "auto",
            });
            return capitalize(rtf.format(0, "day"));
        } else if (messageDate.getTime() === yesterday.getTime()) {
            const rtf = new Intl.RelativeTimeFormat(undefined, {
                numeric: "auto",
            });
            return capitalize(rtf.format(-1, "day"));
        } else {
            return date.toLocaleDateString(undefined, {
                month: "short",
                day: "numeric",
            });
        }
    };

    pages.forEach((page) => {
        page.forEach((message) => {
            const messageDate = message.createdAt.toDateString();
            if (messageDate != lastDate) {
                if (lastDate)
                    messageElements.push(
                        <div className="flex items-center justify-center py-2 w-full">
                            <Separator className="flex-1" />
                            <span className="mx-4 text-sm text-muted-foreground">
                                {formatMessageDate(new Date(lastDate))}
                            </span>
                            <Separator className="flex-1" />
                        </div>,
                    );
                lastDate = messageDate;
            }

            messageElements.push(
                <div key={message.id} className="w-full">
                    <ChatMessage message={message} />
                </div>,
            );
        });
    });

    return messageElements;
}
