import { useState, useEffect, useCallback } from 'react';
import { useSocket } from '../contexts/SocketContext.jsx';
import { useAuth } from '../contexts/AuthContext.jsx';
import { useToast } from '../contexts/ToastContext.jsx';
import { api } from '../utils/api.js';
import Sidebar from '../components/Sidebar.jsx';
import ChatWindow from '../components/ChatWindow.jsx';
import ProfileModal from '../components/ProfileModal.jsx';
import UserManagerModal from '../components/UserManagerModal.jsx';
import SettingsModal from '../components/SettingsModal.jsx';
import NewChatModal from '../components/NewChatModal.jsx';
import GlobalBar from '../components/GlobalBar.jsx';
import AboutModal from '../components/AboutModal.jsx';
import HelpModal from '../components/HelpModal.jsx';
import './Chat.css';

function urlBase64ToUint8Array(base64String) {
  const padding = '='.repeat((4 - base64String.length % 4) % 4);
  const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
  const rawData = window.atob(base64);
  const outputArray = new Uint8Array(rawData.length);
  for (let i = 0; i < rawData.length; ++i) outputArray[i] = rawData.charCodeAt(i);
  return outputArray;
}

export default function Chat() {
  const { socket } = useSocket();
  const { user } = useAuth();
  const toast = useToast();

  const [groups, setGroups] = useState({ publicGroups: [], privateGroups: [] });
  const [activeGroupId, setActiveGroupId] = useState(null);
  const [notifications, setNotifications] = useState([]);
  const [unreadGroups, setUnreadGroups] = useState(new Map());
  const [modal, setModal] = useState(null); // 'profile' | 'users' | 'settings' | 'newchat' | 'help'
  const [helpDismissed, setHelpDismissed] = useState(true); // true until status loaded
  const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
  const [showSidebar, setShowSidebar] = useState(true);

  // Check if help should be shown on login
  useEffect(() => {
    api.getHelpStatus()
      .then(({ dismissed }) => {
        setHelpDismissed(dismissed);
        if (!dismissed) setModal('help');
      })
      .catch(() => {});
  }, []);

  useEffect(() => {
    const handle = () => {
      const mobile = window.innerWidth < 768;
      setIsMobile(mobile);
      if (!mobile) setShowSidebar(true);
    };
    window.addEventListener('resize', handle);
    return () => window.removeEventListener('resize', handle);
  }, []);

  const loadGroups = useCallback(() => {
    api.getGroups().then(setGroups).catch(() => {});
  }, []);

  useEffect(() => { loadGroups(); }, [loadGroups]);

  // Register / refresh push subscription
  useEffect(() => {
    if (!('serviceWorker' in navigator) || !('PushManager' in window)) return;

    const registerPush = async () => {
      try {
        const permission = Notification.permission;
        if (permission === 'denied') return;

        const reg = await navigator.serviceWorker.ready;
        const { publicKey } = await fetch('/api/push/vapid-public').then(r => r.json());
        const token = localStorage.getItem('tc_token') || sessionStorage.getItem('tc_token');

        let sub = await reg.pushManager.getSubscription();

        if (!sub) {
          // First time or subscription was lost — request permission then subscribe
          const granted = permission === 'granted'
            ? 'granted'
            : await Notification.requestPermission();
          if (granted !== 'granted') return;
          sub = await reg.pushManager.subscribe({
            userVisibleOnly: true,
            applicationServerKey: urlBase64ToUint8Array(publicKey),
          });
        }

        // Always re-register subscription with the server (keeps it fresh on mobile)
        await fetch('/api/push/subscribe', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
          body: JSON.stringify(sub.toJSON()),
        });
        console.log('[Push] Subscription registered');
      } catch (e) {
        console.warn('[Push] Subscription failed:', e.message);
      }
    };

    registerPush();

    // Bug A fix: re-register push subscription when app returns to foreground
    // Mobile browsers can drop push subscriptions when the app is backgrounded
    const handleVisibility = () => {
      if (document.visibilityState === 'visible') registerPush();
    };
    document.addEventListener('visibilitychange', handleVisibility);
    return () => document.removeEventListener('visibilitychange', handleVisibility);
  }, []);

  // Socket message events to update group previews
  useEffect(() => {
    if (!socket) return;

    const handleNewMsg = (msg) => {
      // Update group preview text
      setGroups(prev => {
        const updateGroup = (g) => g.id === msg.group_id
          ? { ...g, last_message: msg.content || (msg.image_url ? '📷 Image' : ''), last_message_at: msg.created_at, last_message_user_id: msg.user_id }
          : g;
        const updatedPrivate = prev.privateGroups.map(updateGroup)
          .sort((a, b) => {
            if (!a.last_message_at && !b.last_message_at) return 0;
            if (!a.last_message_at) return 1;
            if (!b.last_message_at) return -1;
            return new Date(b.last_message_at) - new Date(a.last_message_at);
          });
        return {
          publicGroups: prev.publicGroups.map(updateGroup),
          privateGroups: updatedPrivate,
        };
      });
      // Don't badge own messages
      if (msg.user_id === user?.id) return;
      // Bug C fix: count unread even in the active group when window is hidden/minimized
      const groupIsActive = msg.group_id === activeGroupId;
      const windowHidden = document.visibilityState === 'hidden';
      setUnreadGroups(prev => {
        if (groupIsActive && !windowHidden) return prev; // visible & active: no badge
        const next = new Map(prev);
        next.set(msg.group_id, (next.get(msg.group_id) || 0) + 1);
        return next;
      });
    };

    const handleNotification = (notif) => {
      if (notif.type === 'private_message') {
        // Badge is already handled by handleNewMsg via message:new socket event.
        // Nothing to do here for the socket path.
      } else {
        setNotifications(prev => [notif, ...prev]);
        toast(`${notif.fromUser?.display_name || notif.fromUser?.name || 'Someone'} mentioned you`, 'default', 4000);
      }
    };

    socket.on('message:new', handleNewMsg);
    socket.on('notification:new', handleNotification);

    // Group list real-time updates
    const handleGroupNew = ({ group }) => {
      // Join the socket room for this new group
      socket.emit('group:join-room', { groupId: group.id });
      // Reload the full group list so name/metadata is correct
      loadGroups();
    };
    const handleGroupDeleted = ({ groupId }) => {
      // Leave the socket room so we stop receiving events for this group
      socket.emit('group:leave-room', { groupId });
      setGroups(prev => ({
        publicGroups: prev.publicGroups.filter(g => g.id !== groupId),
        privateGroups: prev.privateGroups.filter(g => g.id !== groupId),
      }));
      setActiveGroupId(prev => {
        if (prev === groupId) {
          if (isMobile) setShowSidebar(true);
          return null;
        }
        return prev;
      });
      setUnreadGroups(prev => { const next = new Map(prev); next.delete(groupId); return next; });
    };
    const handleGroupUpdated = ({ group }) => {
      setGroups(prev => {
        const update = g => g.id === group.id ? { ...g, ...group } : g;
        return {
          publicGroups: prev.publicGroups.map(update),
          privateGroups: prev.privateGroups.map(update),
        };
      });
    };

    socket.on('group:new', handleGroupNew);
    socket.on('group:deleted', handleGroupDeleted);
    socket.on('group:updated', handleGroupUpdated);

    // Bug B fix: on reconnect, reload groups to catch any messages missed while offline
    const handleReconnect = () => { loadGroups(); };
    socket.on('connect', handleReconnect);

    // Bug B fix: also reload on visibility restore if socket is already connected
    const handleVisibility = () => {
      if (document.visibilityState === 'visible' && socket.connected) {
        loadGroups();
      }
    };
    document.addEventListener('visibilitychange', handleVisibility);

    return () => {
      socket.off('message:new', handleNewMsg);
      socket.off('notification:new', handleNotification);
      socket.off('group:new', handleGroupNew);
      socket.off('group:deleted', handleGroupDeleted);
      socket.off('group:updated', handleGroupUpdated);
      socket.off('connect', handleReconnect);
      document.removeEventListener('visibilitychange', handleVisibility);
    };
  }, [socket, toast, activeGroupId, user, isMobile, loadGroups]);

  const selectGroup = (id) => {
    setActiveGroupId(id);
    if (isMobile) setShowSidebar(false);
    // Clear notifications and unread count for this group
    setNotifications(prev => prev.filter(n => n.groupId !== id));
    setUnreadGroups(prev => { const next = new Map(prev); next.delete(id); return next; });
  };

  // Update page title AND PWA app badge with total unread count
  useEffect(() => {
    const totalUnread = [...unreadGroups.values()].reduce((a, b) => a + b, 0);
    // Strip any existing badge prefix to get the clean base title
    const base = document.title.replace(/^\(\d+\)\s*/, '');
    document.title = totalUnread > 0 ? `(${totalUnread}) ${base}` : base;
    // PWA app icon badge (Chrome/Edge desktop + Android, Safari 16.4+)
    if ('setAppBadge' in navigator) {
      if (totalUnread > 0) {
        navigator.setAppBadge(totalUnread).catch(() => {});
      } else {
        navigator.clearAppBadge().catch(() => {});
      }
    }
  }, [unreadGroups]);

  const activeGroup = [
    ...(groups.publicGroups || []),
    ...(groups.privateGroups || [])
  ].find(g => g.id === activeGroupId);

  return (
    <div className="chat-layout">
      {/* Global top bar — spans full width on desktop, visible on mobile sidebar view */}
      <GlobalBar isMobile={isMobile} showSidebar={showSidebar} />

      <div className="chat-body">
        {(!isMobile || showSidebar) && (
          <Sidebar
            groups={groups}
            activeGroupId={activeGroupId}
            onSelectGroup={selectGroup}
            notifications={notifications}
            unreadGroups={unreadGroups}
            onNewChat={() => setModal('newchat')}
            onProfile={() => setModal('profile')}
            onUsers={() => setModal('users')}
            onSettings={() => setModal('settings')}
            onGroupsUpdated={loadGroups}
            isMobile={isMobile}
            onAbout={() => setModal('about')}
            onHelp={() => setModal('help')}
          />
        )}

        {(!isMobile || !showSidebar) && (
          <ChatWindow
            group={activeGroup}
            onBack={isMobile ? () => { setShowSidebar(true); setActiveGroupId(null); } : null}
            onGroupUpdated={loadGroups}
            onDirectMessage={(g) => { loadGroups(); selectGroup(g.id); }}
          />
        )}
      </div>

      {modal === 'profile' && <ProfileModal onClose={() => setModal(null)} />}
      {modal === 'users' && <UserManagerModal onClose={() => setModal(null)} />}
      {modal === 'settings' && <SettingsModal onClose={() => setModal(null)} />}
      {modal === 'newchat' && <NewChatModal onClose={() => setModal(null)} onCreated={(g) => { loadGroups(); setModal(null); setActiveGroupId(g.id); }} />}
      {modal === 'about' && <AboutModal onClose={() => setModal(null)} />}
      {modal === 'help' && <HelpModal onClose={() => setModal(null)} dismissed={helpDismissed} />}
    </div>
  );
}
