/* eslint-disable @typescript-eslint/no-explicit-any */
import { useCallback, useEffect, useState } from "react";
import { useGetConversations } from "../../hooks/queries/useChatApi";
import { useChatContext } from "../../providers/ChatProvider";
import {
  Conversation as ConversationType,
  ParticipantGroup,
} from "../../types/type";
import CollapsibleSection from "../common/CollapsibleSection";
import useChatUIStore from "../../stores/Zustant";
import VirtualizedChatList from "../common/VirtualizedChatList";

type GroupedServiceChats = {
  [serviceId: string]: {
    serviceTitle: string;
    conversations: ConversationType[];
  };
};

type TabType = "personal" | "service";

const Conversations = () => {
  const { userId, socket } = useChatContext();
  const { data: participantGroups } = useGetConversations(userId);
  const { searchTerm, lastSentMessage, setLastSentMessage } = useChatUIStore();
  const [activeTab, setActiveTab] = useState<TabType>("personal");
  const [conversations, setConversations] = useState<{
    personalChats: ConversationType[];
    groupedServiceChats: GroupedServiceChats;
  }>({ personalChats: [], groupedServiceChats: {} });

  // Process fetched data
  useEffect(() => {
    if (!participantGroups) return;
    const processConversations = (groups: ParticipantGroup[]) => {
      const allPersonalChats: ConversationType[] = [];
      const allServiceChatsMap = new Map<string, GroupedServiceChats[string]>();

      groups.forEach((group) => {
        if (group.personalConversation) {
          allPersonalChats.push(group.personalConversation);
        }

        group.serviceConversations.forEach((serviceGroup) => {
          if (!allServiceChatsMap.has(serviceGroup.serviceId)) {
            allServiceChatsMap.set(serviceGroup.serviceId, {
              serviceTitle: serviceGroup.serviceTitle,
              conversations: [],
            });
          }

          const existing = allServiceChatsMap.get(serviceGroup.serviceId)!;
          existing.conversations.push(...serviceGroup.conversations);
        });
      });

      const sortConversations = (convos: ConversationType[]) =>
        convos.sort(
          (a, b) =>
            new Date(b.lastMessage?.createdAt || b.updatedAt).getTime() -
            new Date(a.lastMessage?.createdAt || a.updatedAt).getTime()
        );

      sortConversations(allPersonalChats);
      allServiceChatsMap.forEach((value) => {
        sortConversations(value.conversations);
      });

      const result = {
        personalChats: allPersonalChats,
        groupedServiceChats: Object.fromEntries(allServiceChatsMap),
      };

      return result;
    };

    setConversations(processConversations(participantGroups));
  }, [participantGroups]);

  // ── Hoisted to component scope so both the socket listener AND the
  //    lastSentMessage effect can call it ─────────────────────────────
  const handleNewMessage = useCallback((newMessage: any) => {
    if (!newMessage?.conversationId) return;

    setConversations((prev) => {
      const personalChats = [...prev.personalChats];
      const groupedServiceChats = { ...prev.groupedServiceChats };

      const updateConversation = (convo: ConversationType) => ({
        ...convo,
        lastMessage: newMessage,
        updatedAt: new Date().toISOString(),
        unreadMessageIds:
          userId !== newMessage.senderId
            ? [...(convo.unreadMessageIds || []), newMessage._id]
            : convo.unreadMessageIds || [],
        unreadMessageCount:
          userId !== newMessage.senderId
            ? (convo.unreadMessageCount || 0) + 1
            : convo.unreadMessageCount || 0,
      });

      const personalIndex = personalChats.findIndex(
        (c) => c._id === newMessage.conversationId
      );
      if (personalIndex >= 0) {
        personalChats[personalIndex] = updateConversation(personalChats[personalIndex]);
        return { personalChats, groupedServiceChats };
      }

      for (const serviceId in groupedServiceChats) {
        const serviceIndex = groupedServiceChats[serviceId].conversations.findIndex(
          (c) => c._id === newMessage.conversationId
        );
        if (serviceIndex >= 0) {
          const updatedConversations = [...groupedServiceChats[serviceId].conversations];
          updatedConversations[serviceIndex] = updateConversation(updatedConversations[serviceIndex]);
          groupedServiceChats[serviceId] = {
            ...groupedServiceChats[serviceId],
            conversations: updatedConversations,
          };
          return { personalChats, groupedServiceChats };
        }
      }

      // Fallback: brand-new conversation not yet in local state
      personalChats.push({
        _id: newMessage.conversationId,
        participants: [newMessage.senderId, newMessage.receiverId],
        lastMessage: newMessage,
        updatedAt: new Date().toISOString(),
        unreadMessageIds: userId !== newMessage.senderId ? [newMessage._id] : [],
        unreadMessageCount: userId !== newMessage.senderId ? 1 : 0,
        type: "personal",
        createdAt: new Date().toISOString(),
      } as any);

      return { personalChats, groupedServiceChats };
    });
  }, [userId]);

  // Real-time update listeners
  useEffect(() => {
    if (!socket) return;

    const handleMessageReadAck = (data: {
      messageIds: string[];
      chatId: string;
    }) => {
      const { chatId, messageIds } = data;

      setConversations((prev) => {
        const personalChats = [...prev.personalChats];
        const groupedServiceChats = { ...prev.groupedServiceChats };

        const updateRead = (convo: ConversationType) => {
          if (convo._id !== chatId) return convo;
          const updatedUnread = (convo.unreadMessageIds || []).filter(
            (id) => !messageIds.includes(id)
          );
          return {
            ...convo,
            unreadMessageIds: updatedUnread,
            unreadMessageCount: updatedUnread.length,
          };
        };

        const personalIndex = personalChats.findIndex((c) => c._id === chatId);
        if (personalIndex >= 0) {
          personalChats[personalIndex] = updateRead(
            personalChats[personalIndex]
          );
          return { personalChats, groupedServiceChats };
        }

        for (const serviceId in groupedServiceChats) {
          const convos = groupedServiceChats[serviceId].conversations;
          const convoIndex = convos.findIndex((c) => c._id === chatId);
          if (convoIndex >= 0) {
            const updatedConvos = [...convos];
            updatedConvos[convoIndex] = updateRead(updatedConvos[convoIndex]);
            groupedServiceChats[serviceId] = {
              ...groupedServiceChats[serviceId],
              conversations: updatedConvos,
            };
            return { personalChats, groupedServiceChats };
          }
        }

        return prev;
      });
    };

    const messageListener = (event: MessageEvent) => {
      try {
        const parsed = JSON.parse(event.data);

        if (parsed.event === "newMessage") {
          // Actual message is nested at parsed.data.data — same structure as Messages.tsx
          handleNewMessage(parsed?.data?.data);
        } else if (parsed.event === "messageStatusUpdated" && parsed.data?.status === "read") {
          const rawId = parsed.data.messageId ?? parsed.data.messageIds;
          handleMessageReadAck({
            messageIds: Array.isArray(rawId) ? rawId : [rawId].filter(Boolean),
            chatId: parsed.data.chatId,
          });
        }
      } catch (e) {
        console.error("Error parsing socket message:", e);
      }
    };

    socket.addEventListener("message", messageListener);
    return () => socket.removeEventListener("message", messageListener);
  }, [socket, handleNewMessage]);

  // React to messages sent by the current user (no server echo needed)
  useEffect(() => {
    if (!lastSentMessage) return;
    handleNewMessage(lastSentMessage);
    setLastSentMessage(null);
  }, [lastSentMessage, handleNewMessage, setLastSentMessage]);

  // const isEmpty =
  //   activeTab === "personal"
  //     ? conversations.personalChats.length === 0
  //     : Object.keys(conversations.groupedServiceChats).length === 0;

  const lowerSearch = searchTerm?.toLowerCase().trim();

  // Filter personal chats
  const filteredPersonalChats = !lowerSearch
    ? conversations.personalChats
    : conversations.personalChats.filter((convo) => {
        const details = Array.isArray(convo.participantDetails)
          ? convo.participantDetails
          : [convo.participantDetails].filter(Boolean);
        return details.some((p: any) => p?.name?.toLowerCase().includes(lowerSearch));
      });

  // Filter service chats
  const filteredGroupedServiceChats: GroupedServiceChats = !lowerSearch
    ? conversations.groupedServiceChats
    : Object.fromEntries(
        Object.entries(conversations.groupedServiceChats)
          .map(([serviceId, group]) => {
            const details = (convo: ConversationType) => {
              const d = Array.isArray(convo.participantDetails)
                ? convo.participantDetails
                : [convo.participantDetails].filter(Boolean);
              return d.some((p: any) => p?.name?.toLowerCase().includes(lowerSearch));
            };
            const filteredConvos = group.conversations.filter(
              (convo) =>
                details(convo) ||
                group.serviceTitle?.toLowerCase().includes(lowerSearch) ||
                convo.serviceTitle?.toLowerCase().includes(lowerSearch)
            );
            return [serviceId, { ...group, conversations: filteredConvos }] as [string, GroupedServiceChats[string]];
          })
          .filter(([, group]) => group.conversations.length > 0)
      );

  // Improved empty state logic
  const showPersonalTab =
    activeTab === "personal" && filteredPersonalChats.length > 0;
  const showServiceTab =
    activeTab === "service" &&
    Object.keys(filteredGroupedServiceChats).length > 0;
  const isEmpty = !showPersonalTab && !showServiceTab;

  // Calculate unread counts for tabs
  const personalUnreadCount = conversations.personalChats.reduce(
    (total, convo) => total + (convo.unreadMessageCount || 0),
    0
  );

  const serviceUnreadCount = Object.values(conversations.groupedServiceChats)
    .flatMap((group) => group.conversations)
    .reduce((total, convo) => total + (convo.unreadMessageCount || 0), 0);

  return (
    <div className="chat-list__body">
      <div className="chat-tabs" role="tablist">
        <button
          type="button"
          role="tab"
          aria-selected={activeTab === "personal"}
          className={`chat-tab${activeTab === "personal" ? " chat-tab--active" : ""}`}
          onClick={() => setActiveTab("personal")}
        >
          Personal
          {personalUnreadCount > 0 && (
            <span className="chat-tab__count">{personalUnreadCount}</span>
          )}
        </button>
        <button
          type="button"
          role="tab"
          aria-selected={activeTab === "service"}
          className={`chat-tab${activeTab === "service" ? " chat-tab--active" : ""}`}
          onClick={() => setActiveTab("service")}
        >
          Service
          {serviceUnreadCount > 0 && (
            <span className="chat-tab__count">{serviceUnreadCount}</span>
          )}
        </button>
      </div>

      <div className="chat-list__scroll">
        {isEmpty ? (
          <div className="chat-empty chat-empty--list">
            <p className="chat-empty__title">No conversations</p>
            <p className="chat-empty__text">
              {activeTab === "personal"
                ? "You have no personal messages yet."
                : "You have no service messages yet."}
            </p>
          </div>
        ) : (
          <>
            {activeTab === "personal" && filteredPersonalChats.length > 0 && (
              <VirtualizedChatList conversations={filteredPersonalChats} />
            )}

            {activeTab === "service" &&
              Object.entries(filteredGroupedServiceChats).length > 0 &&
              Object.entries(filteredGroupedServiceChats).map(
                ([serviceId, { serviceTitle, conversations: serviceConvos }]) => (
                  <CollapsibleSection
                    key={serviceId}
                    title={serviceTitle}
                    defaultOpen={false}
                  >
                    <VirtualizedChatList conversations={serviceConvos} bounded />
                  </CollapsibleSection>
                )
              )}
          </>
        )}
      </div>
    </div>
  );
};

export default Conversations;