import { useEffect, useState } from 'react';
import { Q } from '@nozbe/watermelondb';
import { database } from 'src/watermelondb';
import Message from 'src/watermelondb/models/Message';
import { makeChatKey } from '../data/message.sync';

export function useMessagesLive(params: {
  chatUid?: number;
  groupChatToken?: string;
  limit: number;
  aroundMessageId?: number;
}) {
  const [messages, setMessages] = useState<Message[]>([]);

  useEffect(() => {
    const chatKey = makeChatKey({ chatUid: params.chatUid, groupChatToken: params.groupChatToken });
    const col = database.get<Message>('messages');
    let unsubBefore: any;
    let unsubAfter: any;

    if (!params.aroundMessageId) {
      const sub = col
        .query(Q.where('chat_key', chatKey), Q.sortBy('sent_at', Q.desc), Q.take(params.limit))
        .observeWithColumns([
          'text',
          'status',
          'reactions',
          'edits',
          'reply_to_id',
          'attachment',
          'is_sending'
        ])
        .subscribe(setMessages);

      return () => sub.unsubscribe();
    }
    const targetId = params.aroundMessageId;
    const beforeLimit = 50;
    const afterLimit = 50;

    let before: Message[] = [];
    let after: Message[] = [];

    const emit = () => {
      const merged = [...before, ...after];

      const map = new Map<number, Message>();
      merged.forEach((m) => {
        if (m.messageId != null) {
          map.set(m.messageId, m);
        }
      });

      const sorted = Array.from(map.values()).sort(
        (a, b) => new Date(b.sentAt).getTime() - new Date(a.sentAt).getTime()
      );

      setMessages(sorted);
    };

    unsubBefore = col
      .query(
        Q.where('chat_key', chatKey),
        Q.where('message_id', Q.lte(targetId)),
        Q.sortBy('sent_at', Q.desc),
        Q.take(beforeLimit)
      )
      .observe()
      .subscribe((rows) => {
        before = rows;
        emit();
      });

    unsubAfter = col
      .query(
        Q.where('chat_key', chatKey),
        Q.where('message_id', Q.gt(targetId)),
        Q.sortBy('sent_at', Q.asc),
        Q.take(afterLimit)
      )
      .observe()
      .subscribe((rows) => {
        after = rows;
        emit();
      });

    return () => {
      unsubBefore?.unsubscribe();
      unsubAfter?.unsubscribe();
    };
  }, [params.chatUid, params.groupChatToken, params.aroundMessageId]);

  return messages;
}
