import React, { createContext, useContext, useState, useCallback, useEffect, useRef, ReactNode } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useLocation } from 'react-router-dom';
import { nextcloudApi } from '../services/nextcloud';
import { useLayout } from './LayoutContext';
import { useNotification } from './NotificationContext';
import type { NextcloudConversation } from '../types/nextcloud.types';

interface ChatContextType {
  rooms: NextcloudConversation[];
  selectedRoomToken: string | null;
  selectRoom: (token: string | null) => void;
  connected: boolean;
  loginName: string | null;
  isActive: boolean;
}

const ChatContext = createContext<ChatContextType | undefined>(undefined);

interface ChatProviderProps {
  children: ReactNode;
}

export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
  const [selectedRoomToken, setSelectedRoomToken] = useState<string | null>(null);
  const { chatPanelOpen } = useLayout();
  const { showNotificationToast } = useNotification();
  const queryClient = useQueryClient();
  const location = useLocation();
  const onChatPage = location.pathname === '/chat';
  const prevPanelOpenRef = useRef(chatPanelOpen);
  const prevOnChatPageRef = useRef(onChatPage);
  const prevUnreadRef = useRef<Map<string, number>>(new Map());

  // Invalidate rooms/connection when panel opens so data is fresh immediately
  useEffect(() => {
    if (chatPanelOpen && !prevPanelOpenRef.current) {
      queryClient.invalidateQueries({ queryKey: ['nextcloud', 'connection'] });
      queryClient.invalidateQueries({ queryKey: ['nextcloud', 'rooms'] });
    }
    prevPanelOpenRef.current = chatPanelOpen;
  }, [chatPanelOpen, queryClient]);

  // Invalidate rooms/connection when navigating to the chat page
  useEffect(() => {
    if (onChatPage && !prevOnChatPageRef.current) {
      queryClient.invalidateQueries({ queryKey: ['nextcloud', 'connection'] });
      queryClient.invalidateQueries({ queryKey: ['nextcloud', 'rooms'] });
    }
    prevOnChatPageRef.current = onChatPage;
  }, [onChatPage, queryClient]);

  const isActive = chatPanelOpen || onChatPage;

  const { data: connData } = useQuery({
    queryKey: ['nextcloud', 'connection'],
    queryFn: () => nextcloudApi.getConversations(),
    refetchInterval: isActive ? 5000 : 15000,
    retry: false,
  });

  const isConnected = connData?.connected ?? false;

  const { data } = useQuery({
    queryKey: ['nextcloud', 'rooms'],
    queryFn: () => nextcloudApi.getRooms(),
    refetchInterval: isActive ? 5000 : 15000,
    enabled: isConnected,
  });

  const rooms = data?.rooms ?? [];
  const connected = data?.connected ?? false;
  const loginName = data?.loginName ?? null;

  const isInitializedRef = useRef(false);

  // Reset initialization flag when disconnected
  useEffect(() => {
    if (!isConnected) {
      isInitializedRef.current = false;
    }
  }, [isConnected]);

  // Detect new unread messages while panel is closed and not on chat page — show toast
  useEffect(() => {
    if (!rooms.length) return;
    const prev = prevUnreadRef.current;

    if (!isInitializedRef.current) {
      // First load (or after reconnect) — initialize without toasting
      for (const room of rooms) {
        prev.set(room.token, room.unreadMessages);
      }
      isInitializedRef.current = true;
      return;
    }

    for (const room of rooms) {
      const prevCount = prev.get(room.token) ?? 0;
      if (!chatPanelOpen && !onChatPage && room.unreadMessages > prevCount) {
        showNotificationToast(room.displayName, 'info');
      }
      prev.set(room.token, room.unreadMessages);
    }

    // Prune entries for rooms no longer in the list
    const currentTokens = new Set(rooms.map((r) => r.token));
    for (const key of prev.keys()) {
      if (!currentTokens.has(key)) prev.delete(key);
    }
  }, [rooms, chatPanelOpen, onChatPage, showNotificationToast]);

  const selectRoom = useCallback((token: string | null) => {
    setSelectedRoomToken(token);
  }, []);

  const value: ChatContextType = {
    rooms,
    selectedRoomToken,
    selectRoom,
    connected,
    loginName,
    isActive,
  };

  return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
};

export const useChat = (): ChatContextType => {
  const context = useContext(ChatContext);
  if (context === undefined) {
    throw new Error('useChat must be used within a ChatProvider');
  }
  return context;
};
