import { noopAsync } from "../../js";
import { SMOOTH_SCROLL_ON_RECEIVE } from "../Singleton";
import { RendererRoutines } from "../types";

export const SimpleRenderer: RendererRoutines = {
    init: async (renderer, id, nearby, smooth) => {
        if (renderer.client!.websocket.connected) {
            if (nearby)
                renderer
                    .client!.channels.get(id)!
                    .fetchMessagesWithUsers({ nearby, limit: 100 })
                    .then(({ messages }) => {
                        messages.sort((a, b) => a._id.localeCompare(b._id));
                        renderer.setState(
                            id,
                            {
                                type: "RENDER",
                                messages,
                                atTop: false,
                                atBottom: false,
                            },
                            { type: "ScrollToView", id: nearby },
                        );
                    });
            else
                renderer
                    .client!.channels.get(id)!
                    .fetchMessagesWithUsers({})
                    .then(({ messages }) => {
                        messages.reverse();
                        renderer.setState(
                            id,
                            {
                                type: "RENDER",
                                messages,
                                atTop: messages.length < 50,
                                atBottom: true,
                            },
                            { type: "ScrollToBottom", smooth },
                        );
                    });
        } else {
            renderer.setState(id, { type: "WAITING_FOR_NETWORK" });
        }
    },
    receive: async (renderer, message) => {
        if (message.channel_id !== renderer.channel) return;
        if (renderer.state.type !== "RENDER") return;
        if (renderer.state.messages.find((x) => x._id === message._id)) return;
        if (!renderer.state.atBottom) return;

        let messages = [...renderer.state.messages, message];
        let atTop = renderer.state.atTop;
        if (messages.length > 150) {
            messages = messages.slice(messages.length - 150);
            atTop = false;
        }

        renderer.setState(
            message.channel_id,
            {
                ...renderer.state,
                messages,
                atTop,
            },
            { type: "StayAtBottom", smooth: SMOOTH_SCROLL_ON_RECEIVE },
        );
    },
    edit: noopAsync,
    delete: async (renderer, id) => {
        const channel = renderer.channel;
        if (!channel) return;
        if (renderer.state.type !== "RENDER") return;

        const messages = [...renderer.state.messages];
        const index = messages.findIndex((x) => x._id === id);

        if (index > -1) {
            messages.splice(index, 1);

            renderer.setState(
                channel,
                {
                    ...renderer.state,
                    messages,
                },
                { type: "StayAtBottom" },
            );
        }
    },
    loadTop: async (renderer, generateScroll) => {
        const channel = renderer.channel;
        if (!channel) return;

        const state = renderer.state;
        if (state.type !== "RENDER") return;
        if (state.atTop) return;

        const { messages: data } = await renderer
            .client!.channels.get(channel)!
            .fetchMessagesWithUsers({
                before: state.messages[0]._id,
            });

        if (data.length === 0) {
            return renderer.setState(channel, {
                ...state,
                atTop: true,
            });
        }

        data.reverse();
        let messages = [...data, ...state.messages];

        let atTop = false;
        if (data.length < 50) {
            atTop = true;
        }

        let atBottom = state.atBottom;
        if (messages.length > 150) {
            messages = messages.slice(0, 150);
            atBottom = false;
        }

        renderer.setState(
            channel,
            { ...state, atTop, atBottom, messages },
            generateScroll(messages[messages.length - 1]._id),
        );
    },
    loadBottom: async (renderer, generateScroll) => {
        const channel = renderer.channel;
        if (!channel) return;

        const state = renderer.state;
        if (state.type !== "RENDER") return;
        if (state.atBottom) return;

        const { messages: data } = await renderer
            .client!.channels.get(channel)!
            .fetchMessagesWithUsers({
                after: state.messages[state.messages.length - 1]._id,
                sort: "Oldest",
            });

        if (data.length === 0) {
            return renderer.setState(channel, {
                ...state,
                atBottom: true,
            });
        }

        let messages = [...state.messages, ...data];

        let atBottom = false;
        if (data.length < 50) {
            atBottom = true;
        }

        let atTop = state.atTop;
        if (messages.length > 150) {
            messages = messages.slice(messages.length - 150);
            atTop = false;
        }

        renderer.setState(
            channel,
            { ...state, atTop, atBottom, messages },
            generateScroll(messages[0]._id),
        );
    },
};