import { InfoCircleOutlined, MessageOutlined, ShrinkOutlined, SyncOutlined } from "@ant-design/icons";
import { useApolloClient, useLazyQuery, useQuery } from "@apollo/client/react";
import { Badge, Card, Col, Row, Space, Tag, Tooltip, Typography } from "antd";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { CONVERSATION_LIST_QUERY, UNREAD_CONVERSATION_COUNT } from "../../graphql/conversations.queries";
import { toggleChatVisible } from "../../redux/messaging/messaging.actions";
import { selectChatVisible, selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
import ChatConversationListComponent from "../chat-conversation-list/chat-conversation-list.component";
import ChatConversationContainer from "../chat-conversation/chat-conversation.container";
import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";

import "./chat-popup.styles.scss";
import { useSocket } from "../../contexts/SocketIO/useSocket.js";
import { selectDarkMode } from "../../redux/application/application.selectors.js";

const mapStateToProps = createStructuredSelector({
  selectedConversation: selectSelectedConversation,
  chatVisible: selectChatVisible,
  isDarkMode: selectDarkMode
});

const mapDispatchToProps = (dispatch) => ({
  toggleChatVisible: () => dispatch(toggleChatVisible())
});

export function ChatPopupComponent({ chatVisible, selectedConversation, toggleChatVisible, isDarkMode }) {
  const { t } = useTranslation();
  const { socket } = useSocket();
  const client = useApolloClient();

  // When socket is connected, we do NOT poll (socket should push updates).
  // When disconnected, we poll as a fallback.
  const [pollInterval, setPollInterval] = useState(0);

  // Ensure conversations query runs once on initial page load (component mount).
  const hasLoadedConversationsOnceRef = useRef(false);

  // Preserve the last known unread aggregate count so the badge doesn't "vanish"
  // when UNREAD_CONVERSATION_COUNT gets skipped after socket connects.
  const [unreadAggregateCount, setUnreadAggregateCount] = useState(0);

  // Lazy query for conversations (executed manually)
  const [getConversations, { loading, data, refetch, called }] = useLazyQuery(CONVERSATION_LIST_QUERY, {
    fetchPolicy: "network-only",
    nextFetchPolicy: "network-only",
    ...(pollInterval > 0 ? { pollInterval } : {})
  });

  // Query for unread count when chat is not visible and socket is not connected.
  // (Once socket connects, we stop this query; we keep the last known value in state.)
  const { data: unreadData, error: unreadError } = useQuery(UNREAD_CONVERSATION_COUNT, {
    fetchPolicy: "network-only",
    nextFetchPolicy: "network-only",
    skip: chatVisible || socket?.connected,
    pollInterval: socket?.connected ? 0 : 60 * 1000
  });

  // Handle unread count updates in useEffect
  useEffect(() => {
    if (unreadData) {
      const nextCount = unreadData?.messages_aggregate?.aggregate?.count;
      if (typeof nextCount === "number") setUnreadAggregateCount(nextCount);
    }
  }, [unreadData]);

  // Handle unread count errors in useEffect
  useEffect(() => {
    if (unreadError) {
      // Keep last known count; do not force badge to zero on transient failures
      console.warn("UNREAD_CONVERSATION_COUNT failed:", unreadError?.message || unreadError);
    }
  }, [unreadError]);

  // Socket connection status -> polling strategy for CONVERSATION_LIST_QUERY
  useEffect(() => {
    const handleSocketStatus = () => {
      if (socket?.connected) {
        setPollInterval(0); // skip polling if socket connected
      } else {
        setPollInterval(60 * 1000); // fallback polling if disconnected
      }
    };

    handleSocketStatus();

    if (socket) {
      socket.on("connect", handleSocketStatus);
      socket.on("disconnect", handleSocketStatus);
    }

    return () => {
      if (socket) {
        socket.off("connect", handleSocketStatus);
        socket.off("disconnect", handleSocketStatus);
      }
    };
  }, [socket]);

  // Run conversations query exactly once on initial load (component mount)
  useEffect(() => {
    if (hasLoadedConversationsOnceRef.current) return;

    hasLoadedConversationsOnceRef.current = true;

    getConversations({ variables: { offset: 0 } }).catch((err) => {
      // Ignore abort errors (they're expected when component unmounts)
      if (err?.name !== "AbortError") {
        console.error(`Error fetching conversations: ${err?.message || ""}`, err);
      }
    });
  }, []);

  const handleManualRefresh = async () => {
    try {
      if (called && typeof refetch === "function") {
        await refetch({ offset: 0 });
      } else {
        await getConversations({ variables: { offset: 0 } });
      }
    } catch (err) {
      console.error(`Error refreshing conversations: ${err?.message || ""}`, err);
    }
  };

  // Get unread count from the cache (preferred). Fallback to preserved aggregate count.
  const unreadCount = (() => {
    try {
      const cachedData = client.readQuery({
        query: CONVERSATION_LIST_QUERY,
        variables: { offset: 0 }
      });

      const conversations = cachedData?.conversations;

      if (!Array.isArray(conversations) || conversations.length === 0) {
        return unreadAggregateCount;
      }

      const hasUnreadCounts = conversations.some((c) => c?.messages_aggregate?.aggregate?.count != null);
      if (!hasUnreadCounts) {
        return unreadAggregateCount;
      }

      return conversations.reduce((total, conversation) => {
        const unread = conversation?.messages_aggregate?.aggregate?.count || 0;
        return total + unread;
      }, 0);
    } catch {
      return unreadAggregateCount;
    }
  })();

  return (
    <Badge count={unreadCount}>
      <Card size="small">
        {chatVisible ? (
          <div className={`chat-popup ${isDarkMode ? "chat-popup--dark" : "chat-popup--light"}`}>
            <Space align="center">
              <Typography.Title level={4}>{t("messaging.labels.messaging")}</Typography.Title>
              <ChatNewConversation />
              <Tooltip title={t("messaging.labels.recentonly")}>
                <InfoCircleOutlined />
              </Tooltip>

              <SyncOutlined style={{ cursor: "pointer" }} onClick={handleManualRefresh} />

              {!socket?.connected && <Tag color="yellow">{t("messaging.labels.nopush")}</Tag>}
            </Space>

            <ShrinkOutlined
              onClick={() => toggleChatVisible()}
              style={{ position: "absolute", right: ".5rem", top: ".5rem" }}
            />

            <Row gutter={[8, 8]} className="chat-popup-content">
              <Col span={8}>
                {loading ? (
                  <LoadingSpinner />
                ) : (
                  <ChatConversationListComponent conversationList={data ? data.conversations : []} />
                )}
              </Col>
              <Col span={16}>{selectedConversation ? <ChatConversationContainer /> : null}</Col>
            </Row>
          </div>
        ) : (
          <div onClick={() => toggleChatVisible()} style={{ cursor: "pointer" }}>
            <MessageOutlined className="chat-popup-info-icon" />
            <strong>{t("messaging.labels.messaging")}</strong>
          </div>
        )}
      </Card>
    </Badge>
  );
}

export default connect(mapStateToProps, mapDispatchToProps)(ChatPopupComponent);
