import { useDialog } from "@/app/providers/DialogProvider/useDialog";
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
import { Message, MessageSystem } from "./Message";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { usePublicKey } from "@/app/providers/AccountProvider/usePublicKey";
import { MessageSkeleton } from "../MessageSkeleton/MessageSkeleton";
import { ScrollArea } from "@mantine/core";
import { MESSAGE_AVATAR_NO_RENDER_TIME_DIFF_S, SCROLL_TOP_IN_MESSAGES_TO_VIEW_AFFIX } from "@/app/constants";
import { DialogAffix } from "../DialogAffix/DialogAffix";
import { useSetting } from "@/app/providers/SettingsProvider/useSetting";

export function Messages() {
    const colors = useRosettaColors();
    const publicKey = usePublicKey();
    const { messages, dialog, loadMessagesToTop, loading } = useDialog();

    const viewportRef = useRef<HTMLDivElement | null>(null);
    const lastMessageRef = useRef<HTMLDivElement | null>(null);
    const contentRef = useRef<HTMLDivElement | null>(null);
    const shouldAutoScrollRef = useRef(true);
    const isFirstRenderRef = useRef(true);
    const previousScrollHeightRef = useRef(0);
    const distanceFromButtomRef = useRef(0);
    const distanceFromTopRef = useRef(0);

    const [affix, setAffix] = useState(false);
    const [wallpaper] = useSetting<string>
        ('wallpaper', '');


    const scrollToBottom = useCallback((smooth: boolean = false) => {
        if (!viewportRef.current) return;

        requestAnimationFrame(() => {
            if (!viewportRef.current) return;

            viewportRef.current.scrollTo({
                top: viewportRef.current.scrollHeight,
                behavior: smooth ? 'smooth' : 'auto'
            });
        });
    }, []);

    // Сброс состояния при смене диалога
    useEffect(() => {
        isFirstRenderRef.current = true;
        shouldAutoScrollRef.current = true;
        previousScrollHeightRef.current = 0;
        setAffix(false);
    }, [dialog]);

    // IntersectionObserver - отслеживаем видимость последнего сообщения
    useEffect(() => {
        if (!lastMessageRef.current || !viewportRef.current || loading) return;

        const observer = new IntersectionObserver(
            (entries) => {
                const entry = entries[0];
                //console.info("IntersectionObserver triggered ", entry.isIntersecting);
                //shouldAutoScrollRef.current = entry.isIntersecting;

                // Если последнее сообщение видно, скрываем кнопку "вниз"
                if (entry.isIntersecting) {
                    setAffix(false);
                }
            },
            {
                root: viewportRef.current,
                threshold: 0.1
            }
        );

        observer.observe(lastMessageRef.current);

        return () => observer.disconnect();
    }, [messages.length, loading]);

    useEffect(() => {
        if (!contentRef.current || !viewportRef.current) return;

        const contentEl = contentRef.current;
        //const viewportEl = viewportRef.current;
        let lastHeight = contentEl.scrollHeight;

        const ro = new ResizeObserver(() => {
            const newHeight = contentEl.scrollHeight;
            const grew = newHeight > lastHeight;
            lastHeight = newHeight;

            if (grew && shouldAutoScrollRef.current) {
                scrollToBottom(true);
            }
        });

        ro.observe(contentEl);
        return () => ro.disconnect();
    }, [scrollToBottom]);

    // Первый рендер - скроллим вниз моментально
    useEffect(() => {
        if (loading || messages.length === 0) return;

        if (isFirstRenderRef.current) {
            scrollToBottom(false);
            isFirstRenderRef.current = false;
        }
    }, [loading, messages.length, scrollToBottom]);

    useEffect(() => {
        if(affix){
            shouldAutoScrollRef.current = false;
        } else {
            shouldAutoScrollRef.current = true;
        }
    }, [affix]);

    // Новое сообщение - скроллим если пользователь внизу или это его сообщение
    useEffect(() => {
        if (loading || messages.length === 0 || isFirstRenderRef.current) return;

        const lastMessage = messages[messages.length - 1];

        // Скроллим если пользователь внизу или это его собственное сообщение
        if ((shouldAutoScrollRef.current || lastMessage.from_me) && distanceFromTopRef.current > 10) {
            console.info(distanceFromTopRef.current);
            scrollToBottom(true);
        }
    }, [messages.length, loading, scrollToBottom]);

    // Восстановление позиции после загрузки старых сообщений
    useEffect(() => {
        if (!viewportRef.current || previousScrollHeightRef.current === 0) return;

        const scrollDiff = viewportRef.current.scrollHeight - previousScrollHeightRef.current;
        if (scrollDiff > 0) {
            viewportRef.current.scrollTop = scrollDiff;
            previousScrollHeightRef.current = 0;
        }
    }, [messages.length]);

    const loadMessagesToScrollAreaTop = async () => {
        if (!viewportRef.current) return;

        previousScrollHeightRef.current = viewportRef.current.scrollHeight;
        await loadMessagesToTop();
    };

    const onAffixClick = () => {
        shouldAutoScrollRef.current = true;
        scrollToBottom(true);
    };

    return (
        <ScrollArea.Autosize
            type="hover"
            offsetScrollbars="y"
            scrollHideDelay={1500}
            scrollbarSize={7}
            scrollbars="y"
            h={100}
            style={{ flexGrow: 1 }}
            viewportRef={viewportRef}
            bg={colors.boxColor}
            styles={{
                viewport: {
                    backgroundImage: `url(${wallpaper})`,
                    backgroundSize: 'cover',
                    backgroundPosition: 'center',
                    backgroundRepeat: 'no-repeat',
                    padding: '10px',
                    height: '100%'
                },
                root: {
                    height: '100%'
                }
            }}
            onScrollPositionChange={(scroll) => {
                if (!viewportRef.current) return;

                distanceFromTopRef.current = scroll.y;

                // Загружаем старые сообщения при достижении верха
                if (scroll.y === 0 && !loading && messages.length >= 20) {
                    loadMessagesToScrollAreaTop();
                }

                // Показываем/скрываем кнопку "вниз"
                const distanceFromBottom =
                    (viewportRef.current.scrollHeight - viewportRef.current.clientHeight) - scroll.y;
                distanceFromButtomRef.current = distanceFromBottom;

                setAffix(distanceFromBottom > SCROLL_TOP_IN_MESSAGES_TO_VIEW_AFFIX);
            }}
        >
            <div ref={contentRef}>
                {loading &&
                    <>
                        <MessageSkeleton messageHeight={20}></MessageSkeleton>
                        <MessageSkeleton messageHeight={40}></MessageSkeleton>
                        <MessageSkeleton messageHeight={70}></MessageSkeleton>
                        <MessageSkeleton messageHeight={20}></MessageSkeleton>
                        <MessageSkeleton messageHeight={38}></MessageSkeleton>
                    </>
                }
                {!loading && messages.map((message, index) => {
                    const prevMessage = messages[index - 1];
                    const currentDate = new Date(message.timestamp).toDateString();
                    const prevDate = prevMessage ? new Date(prevMessage.timestamp).toDateString() : null;
                    const showSystem = prevDate !== currentDate;
                    const isLastMessage = index === messages.length - 1;
                    const isLastMessageInStack = isLastMessage || messages[index + 1].from_public_key !== message.from_public_key || (new Date(messages[index + 1].timestamp).toDateString() !== new Date(message.timestamp).toDateString()) || (messages[index + 1].timestamp - message.timestamp) >= (MESSAGE_AVATAR_NO_RENDER_TIME_DIFF_S * 1000) || (messages[index + 1].plain_message == "$a=Group created" || messages[index + 1].plain_message == "$a=Group joined");

                    return (
                        <React.Fragment key={message.message_id}>
                            {showSystem && (
                                <MessageSystem message={
                                    (() => {
                                        const messageDate = new Date(message.timestamp);
                                        const today = new Date();
                                        const yesterday = new Date();
                                        yesterday.setDate(today.getDate() - 1);

                                        const isToday = messageDate.toDateString() === today.toDateString();
                                        const isYesterday = messageDate.toDateString() === yesterday.toDateString();

                                        if (isToday) return "today";
                                        if (isYesterday) return "yesterday";
                                        return messageDate.toLocaleDateString('en-EN', {
                                            day: 'numeric',
                                            month: 'long',
                                            year: 'numeric'
                                        });
                                    })()
                                } />
                            )}
                            {index > 0 &&
                                messages[index - 1].readed == 1 &&
                                message.readed == 0 &&
                                publicKey != message.from_public_key && (
                                    <MessageSystem c={colors.brandColor} message="New messages" />
                                )
                            }
                            <div ref={isLastMessage ? lastMessageRef : undefined}>
                                {message.plain_message != "$a=Group created" && message.plain_message != "$a=Group joined" && (
                                    <Message
                                        is_last_message_in_stack={isLastMessageInStack}
                                        chacha_key_plain={message.chacha_key}
                                        from={message.from_public_key}
                                        message={message.plain_message}
                                        delivered={message.delivered}
                                        timestamp={message.timestamp}
                                        message_id={message.message_id}
                                        attachments={message.attachments}
                                        from_me={message.from_public_key == publicKey}
                                        readed={message.readed == 1 || message.from_public_key == dialog}
                                        avatar_no_render={
                                            index > 0
                                            && messages[index - 1].from_public_key == message.from_public_key
                                            && (new Date(messages[index - 1].timestamp).toDateString() == new Date(message.timestamp).toDateString())
                                            && (message.timestamp - messages[index - 1].timestamp) < (MESSAGE_AVATAR_NO_RENDER_TIME_DIFF_S * 1000)
                                            && (messages[index - 1].plain_message != "$a=Group created" && messages[index - 1].plain_message != "$a=Group joined")
                                        }
                                    />
                                )}
                                {message.plain_message == "$a=Group created" && (
                                    <MessageSystem c={colors.success} message="Group created" />
                                )}
                                {message.plain_message == "$a=Group joined" && (
                                    <MessageSystem c={colors.success} message="You joined the group" />
                                )}
                            </div>
                        </React.Fragment>
                    );
                })}
            </div>
            <DialogAffix mounted={affix} onClick={onAffixClick} />
        </ScrollArea.Autosize>
    )
}