import React, { useState, useEffect, useCallback, useRef } from "react";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { useAuth } from "../../auth/AuthContext";
import { fetchFriends } from "../../api/client";
import { useChat } from "./useChat";
import ChatWindow from "./ChatWindow";
import "./ChatContainer.css";

const ACTIVE_CHATS_KEY = "sociowire:activeChats";
const MINIMIZED_CHATS_KEY = "sociowire:minimizedChats";

// Play notification sound using Web Audio API
function playNotificationSound() {
  try {
    const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    const oscillator = audioCtx.createOscillator();
    const gainNode = audioCtx.createGain();

    oscillator.connect(gainNode);
    gainNode.connect(audioCtx.destination);

    oscillator.frequency.value = 800;
    oscillator.type = "sine";
    gainNode.gain.value = 0.3;

    oscillator.start();
    gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.2);
    oscillator.stop(audioCtx.currentTime + 0.2);
  } catch (e) {
    // Audio not supported
  }
}

export default function ChatContainer() {
  const { t } = useTranslation();
  const { authenticated, loading: authLoading, username } = useAuth();

  const [friends, setFriends] = useState([]);
  const [showContacts, setShowContacts] = useState(false);
  const [activeChats, setActiveChats] = useState([]); // [{ username, avatar }]
  const [minimizedChats, setMinimizedChats] = useState({}); // { username: boolean }
  const [unreadCounts, setUnreadCounts] = useState({}); // { username: number }

  const notificationPermissionRef = useRef("default");
  const minimizedChatsRef = useRef(minimizedChats);
  const activeChatsRef = useRef(activeChats);

  // Keep refs updated
  useEffect(() => {
    minimizedChatsRef.current = minimizedChats;
  }, [minimizedChats]);

  useEffect(() => {
    activeChatsRef.current = activeChats;
  }, [activeChats]);

  // Lock body scroll on mobile when chat is open (prevents keyboard scroll issues)
  useEffect(() => {
    const hasOpenChat = activeChats.some((chat) => !minimizedChats[chat.username]);
    const isMobile = window.innerWidth <= 640;

    if (hasOpenChat && isMobile) {
      // Save current scroll position
      const scrollY = window.scrollY;
      document.body.style.position = 'fixed';
      document.body.style.top = `-${scrollY}px`;
      document.body.style.left = '0';
      document.body.style.right = '0';
      document.body.dataset.chatScrollY = scrollY;
    } else if (document.body.style.position === 'fixed') {
      // Restore scroll position
      const scrollY = document.body.dataset.chatScrollY || 0;
      document.body.style.position = '';
      document.body.style.top = '';
      document.body.style.left = '';
      document.body.style.right = '';
      window.scrollTo(0, parseInt(scrollY, 10));
    }

    return () => {
      if (document.body.style.position === 'fixed') {
        const scrollY = document.body.dataset.chatScrollY || 0;
        document.body.style.position = '';
        document.body.style.top = '';
        document.body.style.left = '';
        document.body.style.right = '';
        window.scrollTo(0, parseInt(scrollY, 10));
      }
    };
  }, [activeChats, minimizedChats]);

  // Request notification permission
  useEffect(() => {
    if ("Notification" in window) {
      notificationPermissionRef.current = Notification.permission;
      if (Notification.permission === "default") {
        Notification.requestPermission().then((permission) => {
          notificationPermissionRef.current = permission;
        });
      }
    }
  }, []);

  // Reference to markAsRead function (will be set after useChat)
  const markAsReadRef = useRef(null);

  // Handle new incoming message
  const handleNewMessage = useCallback((msg) => {
    const senderName = msg.sender_name;

    // Check if chat is open and not minimized
    const isChatOpen = activeChatsRef.current.some((c) => c.username === senderName);
    const isChatMinimized = minimizedChatsRef.current[senderName];
    const isDocumentFocused = document.hasFocus();

    // Chat is visible = open + not minimized + document focused
    const isChatVisible = isChatOpen && !isChatMinimized && isDocumentFocused;

    if (isChatVisible) {
      // Chat is open and user can see the message - mark as read immediately
      if (markAsReadRef.current) {
        markAsReadRef.current(senderName);
      }
    } else {
      // Update unread count if chat is not visible
      setUnreadCounts((prev) => ({
        ...prev,
        [senderName]: (prev[senderName] || 0) + 1,
      }));
    }

    // Show notification if chat is not visible
    const shouldNotify = !isChatVisible;

    if (shouldNotify) {
      // Play notification sound
      playNotificationSound();

      // Show browser notification
      if (notificationPermissionRef.current === "granted") {
        const notification = new Notification(`${senderName}`, {
          body: msg.content?.substring(0, 100) || "New message",
          icon: "/favicon.ico",
          tag: `chat-${senderName}`,
          silent: true, // We play our own sound
        });

        notification.onclick = () => {
          window.focus();
          // Open or unminimize the chat
          const friend = { username: senderName };
          if (!activeChatsRef.current.some((c) => c.username === senderName)) {
            setActiveChats((prev) => [...prev, friend]);
          }
          setMinimizedChats((prev) => ({ ...prev, [senderName]: false }));
          notification.close();
        };
      }
    }
  }, []);

  // Chat hook
  const {
    connected,
    messages,
    typing,
    presence,
    conversations,
    sendMessage,
    sendTyping,
    markAsRead,
    fetchMessages,
    fetchConversations,
  } = useChat({
    username,
    enabled: authenticated,
    onNewMessage: handleNewMessage,
  });

  // Keep markAsReadRef updated so handleNewMessage can use it
  useEffect(() => {
    markAsReadRef.current = markAsRead;
  }, [markAsRead]);

  // Load friends when authenticated
  useEffect(() => {
    if (!authenticated) {
      setFriends([]);
      return;
    }

    const loadFriends = async () => {
      const res = await fetchFriends();
      if (res?.ok && res.friends) {
        setFriends(res.friends);
      }
    };

    loadFriends();
  }, [authenticated]);

  // Load conversations to get initial unread counts
  useEffect(() => {
    if (!authenticated || !connected) return;

    const loadConversations = async () => {
      const convs = await fetchConversations();
      if (convs && convs.length > 0) {
        const newUnread = {};
        convs.forEach((c) => {
          if (c.unread_count > 0) {
            newUnread[c.username] = c.unread_count;
          }
        });
        if (Object.keys(newUnread).length > 0) {
          setUnreadCounts((prev) => ({ ...prev, ...newUnread }));
        }
      }
    };

    loadConversations();
  }, [authenticated, connected, fetchConversations]);

  // Load active chats and minimized state from localStorage
  useEffect(() => {
    try {
      const savedChats = localStorage.getItem(ACTIVE_CHATS_KEY);
      if (savedChats) {
        const parsed = JSON.parse(savedChats);
        if (Array.isArray(parsed)) {
          setActiveChats(parsed);
        }
      }
      const savedMinimized = localStorage.getItem(MINIMIZED_CHATS_KEY);
      if (savedMinimized) {
        const parsed = JSON.parse(savedMinimized);
        if (typeof parsed === 'object' && parsed !== null) {
          setMinimizedChats(parsed);
        }
      }
    } catch {}
  }, []);

  // Save active chats to localStorage
  useEffect(() => {
    try {
      localStorage.setItem(ACTIVE_CHATS_KEY, JSON.stringify(activeChats));
    } catch {}
  }, [activeChats]);

  // Save minimized state to localStorage
  useEffect(() => {
    try {
      localStorage.setItem(MINIMIZED_CHATS_KEY, JSON.stringify(minimizedChats));
    } catch {}
  }, [minimizedChats]);

  // Fetch messages for restored active chats when connection is established
  const hasLoadedRestoredChats = useRef(false);
  useEffect(() => {
    if (connected && activeChats.length > 0 && !hasLoadedRestoredChats.current) {
      hasLoadedRestoredChats.current = true;
      activeChats.forEach((chat) => {
        fetchMessages(chat.username);
      });
    }
  }, [connected, activeChats, fetchMessages]);

  // Refresh messages and unread counts when page becomes visible (mobile resume)
  useEffect(() => {
    const handleVisibilityChange = async () => {
      if (document.visibilityState === 'visible' && authenticated) {
        console.log('[Chat] Page visible, refreshing data...');

        // Refresh messages for active chats
        if (activeChats.length > 0) {
          activeChats.forEach((chat) => {
            fetchMessages(chat.username);
          });
        }

        // Refresh conversations to update unread counts/badges
        const convs = await fetchConversations();
        if (convs && convs.length > 0) {
          // Build new unread counts from server (source of truth)
          const serverUnread = {};
          convs.forEach((c) => {
            // Use case-insensitive key matching
            serverUnread[c.username.toLowerCase()] = { username: c.username, count: c.unread_count || 0 };
          });

          setUnreadCounts((prev) => {
            const updated = {};
            // For each conversation from server, use server count
            // unless the chat is currently open and not minimized (user is viewing it)
            Object.values(serverUnread).forEach(({ username, count }) => {
              const key = username;
              const isOpenAndVisible = activeChatsRef.current.some(
                (c) => c.username.toLowerCase() === username.toLowerCase()
              ) && !minimizedChatsRef.current[username];

              // If chat is open and visible, keep it at 0 (user can see messages)
              // Otherwise use server count
              updated[key] = isOpenAndVisible ? 0 : count;
            });
            return updated;
          });
        }
      }
    };

    document.addEventListener('visibilitychange', handleVisibilityChange);
    return () => {
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [activeChats, fetchMessages, fetchConversations, authenticated]);


  // Open chat with a friend
  const openChat = useCallback(
    (friend) => {
      if (!authenticated) {
        // Trigger auth modal
        window.dispatchEvent(
          new CustomEvent("sociowire:auth-required", {
            detail: {
              message: t("chat.signInToChat", "Sign in to chat with friends"),
              mode: "login",
            },
          })
        );
        setShowContacts(false);
        return;
      }

      // Save scroll position before any state changes
      const scrollY = window.scrollY;

      const friendUsername = friend.username || friend.name;
      const chatData = {
        username: friendUsername,
        avatar: friend.avatar_url || friend.avatar,
      };

      // Check if already open
      if (!activeChats.some((c) => c.username === chatData.username)) {
        setActiveChats((prev) => [...prev, chatData]);

        // Fetch message history
        fetchMessages(friendUsername);
      }

      // Unminimize if minimized
      setMinimizedChats((prev) => ({ ...prev, [friendUsername]: false }));
      // Clear unread count and mark as read
      setUnreadCounts((prev) => ({ ...prev, [friendUsername]: 0 }));
      markAsRead(friendUsername);
      setShowContacts(false);

      // Restore scroll position after React updates
      requestAnimationFrame(() => {
        window.scrollTo(0, scrollY);
      });
    },
    [authenticated, activeChats, fetchMessages, markAsRead, t]
  );

  // Close a chat
  const closeChat = useCallback((chatUsername) => {
    // Save scroll position before closing
    const scrollY = window.scrollY;

    setActiveChats((prev) => prev.filter((c) => c.username !== chatUsername));
    setMinimizedChats((prev) => {
      const next = { ...prev };
      delete next[chatUsername];
      return next;
    });

    // Restore scroll position after React updates
    requestAnimationFrame(() => {
      window.scrollTo(0, scrollY);
    });
  }, []);

  // Toggle minimize
  const toggleMinimize = useCallback((chatUsername) => {
    const scrollY = window.scrollY;

    setMinimizedChats((prev) => {
      const wasMinimized = prev[chatUsername];
      // Clear unread count and mark as read when unminimizing
      if (wasMinimized) {
        setUnreadCounts((uc) => ({ ...uc, [chatUsername]: 0 }));
        markAsRead(chatUsername);
      }
      return { ...prev, [chatUsername]: !wasMinimized };
    });

    requestAnimationFrame(() => {
      window.scrollTo(0, scrollY);
    });
  }, [markAsRead]);

  // Handle send message
  const handleSend = useCallback(
    (chatUsername) => (content) => {
      sendMessage(chatUsername, content);
    },
    [sendMessage]
  );

  // Handle typing
  const handleTyping = useCallback(
    (chatUsername) => (isTyping) => {
      sendTyping(chatUsername, isTyping);
    },
    [sendTyping]
  );

  // Handle contacts button click
  const handleContactsClick = () => {
    if (!authenticated) {
      // Trigger auth modal
      window.dispatchEvent(
        new CustomEvent("sociowire:auth-required", {
          detail: {
            message: t("chat.signInToChat", "Sign in to chat with friends"),
            mode: "login",
          },
        })
      );
      return;
    }

    // Refresh conversations when opening to get latest activity for sorting
    if (!showContacts) {
      fetchConversations();
    }
    setShowContacts(!showContacts);
  };

  // Calculate total unread count
  const totalUnread = Object.values(unreadCounts).reduce((sum, count) => sum + count, 0);

  // Use portal to render chat outside of normal DOM hierarchy
  // This ensures chat is completely independent and always on top
  return createPortal(
    <>
      {/* Bottom Bar: Active Chat Tabs + Contacts Button */}
      <div className="chat-bottom-bar">
        {/* Active Chat Tabs (minimized chats) */}
        {activeChats.filter(chat => minimizedChats[chat.username]).map((chat) => {
          const unread = unreadCounts[chat.username] || 0;
          return (
            <button
              key={chat.username}
              className={"chat-tab" + (presence[chat.username] ? " online" : "") + (unread > 0 ? " has-unread" : "")}
              onClick={() => toggleMinimize(chat.username)}
            >
              <div className="chat-tab-avatar">
                {chat.avatar ? (
                  <img src={chat.avatar} alt={chat.username} />
                ) : (
                  <span>{(chat.username || "?")[0].toUpperCase()}</span>
                )}
              </div>
              <span className="chat-tab-name">{chat.username}</span>
              {unread > 0 && <span className="chat-tab-unread">{unread}</span>}
              <button
                className="chat-tab-close"
                onClick={(e) => { e.stopPropagation(); closeChat(chat.username); }}
              >
                <i className="fa-solid fa-xmark" />
              </button>
            </button>
          );
        })}

        {/* Contacts Button */}
        <button
          className={"contacts-float-btn" + (connected ? " connected" : "")}
          onClick={handleContactsClick}
        >
          <span className="contact-icon">
            <i className="fa-solid fa-comments" />
          </span>
          <span className="contact-label">{t("common.contacts")}</span>
          {totalUnread > 0 && <span className="contacts-badge">{totalUnread}</span>}
          {authenticated && (
            <span className={"connection-dot" + (connected ? " online" : "")} />
          )}
        </button>
      </div>

      {/* Contacts Dropdown */}
      {showContacts && (
        <div className="contacts-dropdown">
          <div className="contacts-header">
            <span>{t("common.contacts")}</span>
            <button
              type="button"
              className="contacts-close"
              onClick={() => setShowContacts(false)}
            >
              <i className="fa-solid fa-xmark" />
            </button>
          </div>

          {!authenticated ? (
            <div className="contacts-empty">
              {t("friends.signInToSee")}
            </div>
          ) : friends.length === 0 ? (
            <div className="contacts-empty">
              {t("friends.noFriends")}
            </div>
          ) : (
            <div className="contacts-list">
              {/* Sort friends by last activity: conversations first (by date), then others */}
              {[...friends].sort((a, b) => {
                const aUsername = a.username || a.name;
                const bUsername = b.username || b.name;
                const aConv = conversations.find(c => c.username?.toLowerCase() === aUsername?.toLowerCase());
                const bConv = conversations.find(c => c.username?.toLowerCase() === bUsername?.toLowerCase());

                // Friends with conversations come first, sorted by last_message_at
                if (aConv && bConv) {
                  return new Date(bConv.last_message_at) - new Date(aConv.last_message_at);
                }
                if (aConv) return -1;
                if (bConv) return 1;
                // Friends without conversations sorted alphabetically
                return aUsername.localeCompare(bUsername);
              }).map((friend) => {
                const friendUsername = friend.username || friend.name;
                const avatar = friend.avatar_url || friend.avatar;
                const isOnline = presence[friendUsername] || false;
                const unreadCount = unreadCounts[friendUsername] || 0;

                return (
                  <div
                    key={friendUsername}
                    className={"contact-item" + (unreadCount > 0 ? " has-unread" : "")}
                    onClick={() => openChat(friend)}
                  >
                    <div className={"contact-avatar" + (isOnline ? " online" : "")}>
                      {avatar ? (
                        <img src={avatar} alt={friendUsername} />
                      ) : (
                        <span>{(friendUsername || "?")[0].toUpperCase()}</span>
                      )}
                    </div>
                    <span className="contact-name">{friendUsername}</span>
                    {unreadCount > 0 && (
                      <span className="contact-unread-badge">{unreadCount}</span>
                    )}
                    {isOnline && <span className="online-badge" />}
                  </div>
                );
              })}
            </div>
          )}
        </div>
      )}

      {/* Active Chat Windows (only non-minimized) */}
      <div className="chat-windows-container">
        {activeChats
          .filter((chat) => !minimizedChats[chat.username])
          .map((chat, index) => (
            <div
              key={chat.username}
              className="chat-window-wrapper"
              style={{ right: 16 + index * 340 }}
            >
              <ChatWindow
                recipientID={chat.username}
                recipientName={chat.username}
                recipientAvatar={chat.avatar}
                messages={messages[chat.username] || []}
                typing={typing[chat.username] || false}
                online={presence[chat.username] || false}
                minimized={false}
                onSend={handleSend(chat.username)}
                onTyping={handleTyping(chat.username)}
                onClose={() => closeChat(chat.username)}
                onMinimize={() => toggleMinimize(chat.username)}
              />
            </div>
          ))}
      </div>
    </>,
    document.body
  );
}
