import { useEffect, useRef, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { useChatStore } from '../application/chatStore';
import { useAuthStore } from '../../auth/application/authStore';
import { getSocket, disconnectSocket } from '../../../core/infrastructure/socket';
import { ChatApi } from '../infrastructure/chatApi';
import { playNotificationSound, isChatMuted, playCallRingtone, stopCallRingtone } from '../../../core/utils/sounds';
import { useLang } from '../../../core/infrastructure/i18n';
import type { Message, UserBasic, CallInfo, ChatMember } from '../../../core/domain/types';
import { Send, Check, Phone, PhoneOff, Users } from 'lucide-react';
import Sidebar from '../../../core/presentation/layouts/Sidebar';
import GlobalNavBar from '../../../core/presentation/layouts/GlobalNavBar';
import ChatView from './components/ChatView';
import CallModal from '../../calls/presentation/components/CallModal';
import GroupCallModal from '../../calls/presentation/components/GroupCallModal';
import ContactsSidebar from '../../friends/presentation/components/ContactsSidebar';
import SettingsPage from '../../users/presentation/components/SettingsPage';
import UserProfile from '../../users/presentation/components/UserProfile';
import Avatar from '../../../core/presentation/components/ui/Avatar';
import { getMediaUrl } from '../../../core/utils/utils';

export default function ChatPage() {
  const {
    loadChats,
    addMessage,
    updateMessage,
    removeMessage,
    removeMessages,
    hideMessages,
    addReaction,
    removeReaction,
    markRead,
    addTypingUser,
    removeTypingUser,
    updateUserOnlineStatus,
    setPinnedMessage,
    removePinnedMessage,
    clearStore,
    addChat,
  } = useChatStore();
  const { user } = useAuthStore();
  const initialized = useRef(false);

  // Call state
  const [callOpen, setCallOpen] = useState(false);
  const [callTarget, setCallTarget] = useState<UserBasic | null>(null);
  const [callType, setCallType] = useState<'voice' | 'video'>('voice');
  const [incomingCall, setIncomingCall] = useState<CallInfo | null>(null);
  const [callSessionId, setCallSessionId] = useState(0);
  const [deliveryNotification, setDeliveryNotification] = useState<string | null>(null);
  const deliveryTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  // Group call state
  const [groupCallOpen, setGroupCallOpen] = useState(false);
  const [groupCallChatId, setGroupCallChatId] = useState('');
  const [groupCallChatName, setGroupCallChatName] = useState('');
  const [groupCallType, setGroupCallType] = useState<'voice' | 'video'>('voice');
  const [groupCallSessionId, setGroupCallSessionId] = useState(0);

  const [incomingGroupCall, setIncomingGroupCall] = useState<{ chatId: string; from: string; callerInfo: any; callType: string; chatName: string } | null>(null);

  const groupCallOpenRef = useRef(false);
  const groupCallChatIdRef = useRef('');

  const [activeTab, setActiveTab] = useState('chats');
  const { t } = useLang();

  useEffect(() => {
    groupCallOpenRef.current = groupCallOpen;
    groupCallChatIdRef.current = groupCallChatId;
  }, [groupCallOpen, groupCallChatId]);

  useEffect(() => {
    if (initialized.current) return;
    initialized.current = true;
    loadChats();
  }, [loadChats]);

  // Обработка закрытия вкладки — отправить disconnect
  useEffect(() => {
    const handleBeforeUnload = () => {
      const socket = getSocket();
      if (socket) {
        socket.disconnect();
      }
    };

    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  }, []);

  useEffect(() => {
    const socket = getSocket();
    if (!socket) return;

    socket.on('new_message', async (message: Message) => {
      // If this chat isn't in our store yet (e.g. someone just created it and sent a message),
      // fetch chats so the new chat appears in the sidebar immediately
      const { chats } = useChatStore.getState();
      if (!chats.some(c => c.id === message.chatId)) {
        try {
          const allChats = await ChatApi.getChats();
          const newChat = allChats.find(c => c.id === message.chatId);
          if (newChat) {
            // Reset unreadCount to 0 because addMessage below will increment it by 1
            useChatStore.getState().addChat({ ...newChat, unreadCount: 0 });
          }
        } catch (e) {
          console.error('Failed to fetch new chat:', e);
        }
      }
      addMessage(message);
      // Play notification sound for messages from others
      if (message.senderId !== user?.id && !message.storyId && !isChatMuted(message.chatId)) {
        playNotificationSound();
      }
    });

    socket.on('scheduled_delivered', async (message: Message & { _recipientName?: string; _deliveredAt?: string }) => {
      // If chat unknown, fetch it first
      const { chats } = useChatStore.getState();
      if (!chats.some(c => c.id === message.chatId)) {
        try {
          const allChats = await ChatApi.getChats();
          const newChat = allChats.find(c => c.id === message.chatId);
          if (newChat) useChatStore.getState().addChat(newChat);
        } catch (_) { /* ignore */ }
      }
      // A scheduled message was delivered: update it in store (remove scheduledAt)
      updateMessage({ ...message, scheduledAt: null });

      // Show delivery notification to the sender
      if (message.senderId === user?.id && message._recipientName) {
        const time = message._deliveredAt
          ? new Date(message._deliveredAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
          : '';
        const notifText = `${useLang.getState().t('scheduledDelivered')} ${message._recipientName} ${useLang.getState().t('scheduledDeliveredAt')} ${time}`;
        setDeliveryNotification(notifText);
        if (deliveryTimerRef.current) clearTimeout(deliveryTimerRef.current);
        deliveryTimerRef.current = setTimeout(() => setDeliveryNotification(null), 5000);
      }

      // Notify others with sound
      if (message.senderId !== user?.id && !isChatMuted(message.chatId)) {
        playNotificationSound();
      }
    });

    socket.on('message_edited', (data: { messageId: string; chatId: string; content: string; isEdited: boolean }) => {
      updateMessage({ id: data.messageId, chatId: data.chatId, content: data.content, isEdited: data.isEdited } as Message);
    });

    socket.on('new_chat', (chat: any) => {
      addChat(chat);
      socket.emit('join_chat', chat.id);
    });

    socket.on('message_deleted', (data: { messageId: string; chatId: string }) => {
      removeMessage(data.messageId, data.chatId);
    });

    socket.on('messages_deleted', (data: { messageIds: string[]; chatId: string }) => {
      removeMessages(data.messageIds, data.chatId);
    });

    socket.on('messages_hidden', (data: { messageIds: string[]; chatId: string }) => {
      hideMessages(data.messageIds, data.chatId);
    });

    socket.on('reaction_added', (data: { messageId: string; chatId: string; userId: string; username: string; emoji: string }) => {
      console.log('[Socket] reaction_added received:', data);
      addReaction(data.messageId, data.chatId, data.userId, data.username, data.emoji);
    });

    socket.on('reaction_removed', (data: { messageId: string; chatId: string; userId: string; emoji: string }) => {
      console.log('[Socket] reaction_removed received:', data);
      removeReaction(data.messageId, data.chatId, data.userId, data.emoji);
    });

    socket.on('messages_read', (data: any) => {
      const chatId = data.chatId || data.ChatId;
      const userId = data.userId || data.UserId;
      const lastReadSequenceId = data.lastReadSequenceId || data.LastReadSequenceId || 0;

      // Обновляем стейт - добавляем userId в readBy для всех сообщений до lastReadSequenceId
      markRead(chatId, userId, lastReadSequenceId);
    });

    socket.on('user_typing', (data: { chatId: string; userId: string }) => {
      if (data.userId !== user?.id) {
        addTypingUser(data.chatId, data.userId);
        setTimeout(() => removeTypingUser(data.chatId, data.userId), 3000);
      }
    });

    socket.on('user_stopped_typing', (data: { chatId: string; userId: string }) => {
      removeTypingUser(data.chatId, data.userId);
    });

    socket.on('user_online', (data: { userId: string }) => {
      updateUserOnlineStatus(data.userId, true);
    });

    socket.on('user_offline', (data: { userId: string; lastSeen?: string }) => {
      updateUserOnlineStatus(data.userId, false, data.lastSeen);
    });

    socket.on('message_pinned', (data: { chatId: string; message: Message }) => {
      setPinnedMessage(data.chatId, data.message);
    });

    socket.on('message_unpinned', (data: { chatId: string; messageId: string }) => {
      removePinnedMessage(data.chatId, data.messageId);
    });

    socket.on('poll_updated', (message: Message) => {
      updateMessage(message);
    });

    socket.on('call_incoming', async (data: CallInfo) => {
      // Use callerInfo from server if available, otherwise look up from chats
      let callerInfo: UserBasic | null = data.callerInfo || null;
      if (!callerInfo) {
        const { chats } = useChatStore.getState();
        for (const chat of chats) {
          const member = chat.members.find((m) => m.user.id === data.from);
          if (member) {
            callerInfo = member.user;
            break;
          }
        }
      }
      setCallTarget(null); // Clear any previous outgoing target
      setIncomingCall({
        from: data.from,
        offer: data.offer,
        callType: data.callType,
        chatId: data.chatId,
        callerInfo,
      });
      setCallType(data.callType);
      setCallSessionId(id => id + 1);
      setCallOpen(true);
    });

    // Story events - registered globally so they work even when StoryViewer is closed
    socket.on('story_viewed', (data: { storyId: string; userId: string; username: string; displayName: string; avatar: string | null; viewedAt: string; viewCount: number; ownerId: string }) => {
      console.log('[Socket] story_viewed received:', data);
      // Only process if this user is the owner
      if (data.ownerId === user?.id) {
        console.log('[Socket] This is my story, updating view count');
      }
    });

    socket.on('story_reply', (data: { storyId: string; userId: string; username: string; displayName: string; avatar: string | null; content: string; createdAt: string; ownerId: string }) => {
      console.log('[Socket] story_reply received:', data);
      // Only process if this user is the owner
      if (data.ownerId === user?.id) {
        console.log('[Socket] This is my story, got reply:', data.content);
      }
    });

    socket.on('story_reaction', (data: { storyId: string; userId: string; username: string; displayName: string; avatar: string | null; emoji: string; createdAt: string; ownerId: string }) => {
      console.log('[Socket] story_reaction received:', data);
      // Only process if this user is the owner
      if (data.ownerId === user?.id) {
        console.log('[Socket] This is my story, got reaction:', data.emoji);
      }
    });

    socket.on('group_call_incoming', (data: { chatId: string; from: string; callerInfo: any; callType: string }) => {
      if (data.from === user?.id) return;
      if (groupCallOpenRef.current && groupCallChatIdRef.current === data.chatId) return;

      const { chats } = useChatStore.getState();
      const chat = chats.find(c => c.id === data.chatId);
      if (!chat) return;

      playCallRingtone();
      setIncomingGroupCall({
        chatId: data.chatId,
        from: data.from,
        callerInfo: data.callerInfo,
        callType: data.callType,
        chatName: chat.name || 'Group',
      });

      // Auto-dismiss after 15 seconds if ignored
      setTimeout(() => {
        setIncomingGroupCall(prev => {
          if (prev?.chatId === data.chatId) {
            stopCallRingtone();
            return null;
          }
          return prev;
        });
      }, 15000);
    });

    socket.on('group_call_ended', (data: { chatId: string }) => {
      setIncomingGroupCall(prev => {
        if (prev?.chatId === data.chatId) {
          stopCallRingtone();
          return null;
        }
        return prev;
      });
    });

    return () => {
      socket.off('new_message');
      socket.off('scheduled_delivered');
      socket.off('message_edited');
      socket.off('new_chat');
      socket.off('message_deleted');
      socket.off('messages_deleted');
      socket.off('messages_hidden');
      socket.off('reaction_added');
      socket.off('reaction_removed');
      socket.off('messages_read');
      socket.off('user_typing');
      socket.off('user_stopped_typing');
      socket.off('user_online');
      socket.off('user_offline');
      socket.off('message_pinned');
      socket.off('message_unpinned');
      socket.off('call_incoming');
      socket.off('story_viewed');
      socket.off('story_reply');
      socket.off('story_reaction');
      socket.off('group_call_incoming');
      socket.off('group_call_ended');
    };
  }, [user?.id]);

  const handleStartCall = (targetUser: UserBasic, type: 'voice' | 'video') => {
    setCallTarget(targetUser);
    setCallType(type);
    setIncomingCall(null);
    setCallSessionId(id => id + 1);
    setCallOpen(true);
  };

  useEffect(() => {
    const handleCustomCallEvent = ((e: CustomEvent) => {
      if (e.detail?.targetUser && e.detail?.type) {
        handleStartCall(e.detail.targetUser, e.detail.type);
      }
    }) as EventListener;
    window.addEventListener('START_CALL', handleCustomCallEvent);
    return () => window.removeEventListener('START_CALL', handleCustomCallEvent);
  }, []);

  const handleStartGroupCall = (chatId: string, chatName: string, type: 'voice' | 'video') => {
    setGroupCallChatId(chatId);
    setGroupCallChatName(chatName);
    setGroupCallType(type);
    setGroupCallSessionId(id => id + 1);
    setGroupCallOpen(true);
  };

  const handleCloseCall = () => {
    setCallOpen(false);
    setCallTarget(null);
    setIncomingCall(null);
  };

  const handleCloseGroupCall = () => {
    setGroupCallOpen(false);
  };

  const activeChat = useChatStore((state) => state.activeChat);

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      className="h-[100dvh] w-screen flex flex-col lg:flex-row bg-surface-dim overflow-hidden"
    >
      <div className={`${activeChat ? 'hidden lg:block' : 'block'}`}>
        <GlobalNavBar activeTab={activeTab} onTabChange={setActiveTab} />
      </div>

      <main className={`lg:ml-20 flex-1 flex flex-row relative h-full safe-area-bottom`}>
        {activeTab === 'chats' ? (
          <>
            {/* Chat List (Sidebar) */}
            <div
              className={`${activeChat ? 'hidden lg:block' : 'block'} w-full lg:w-[360px] flex-shrink-0 bg-surface-container-low h-full overflow-hidden`}
            >
              <Sidebar />
            </div>

            {/* Selected Chat View (Main Area) */}
            <div
              className={`${activeChat ? 'block' : 'hidden lg:block'} flex-1 h-full min-w-0 bg-surface-container-lowest relative group slide-on-ice`}
            >
              <ChatView onStartCall={handleStartCall} onStartGroupCall={handleStartGroupCall} />
            </div>
          </>
        ) : activeTab === 'contacts' ? (
          <div className="flex-1 flex flex-row h-full overflow-hidden">
            {/* Contacts Sidebar List */}
            <div className="w-full lg:w-[360px] flex-shrink-0 bg-surface-container-low h-full overflow-hidden antialiased">
              <ContactsSidebar onSwitchToChat={() => setActiveTab('chats')} />
            </div>

            {/* Right side placeholder / Profile detail */}
            <div className="hidden lg:flex flex-1 items-center justify-center bg-surface-base h-full relative slide-on-ice">
              <div className="flex flex-col items-center gap-6 max-w-sm text-center">
                <div className="w-24 h-24 rounded-3xl bg-primary/10 flex items-center justify-center text-primary shadow-inner">
                  <Users size={48} className="knot-logo-spin opacity-50" />
                </div>
                <div>
                  <h2 className="text-xl font-bold text-white mb-2">{t('contacts')}</h2>
                  <p className="text-sm text-zinc-500 leading-relaxed max-w-[280px]">
                    {t('selectContactToChat')}
                  </p>
                </div>
                <button
                  onClick={() => setActiveTab('chats')}
                  className="px-8 py-3 rounded-2xl bg-primary text-on-primary shadow-lg shadow-primary/20 hover:scale-105 active:scale-95 transition-all text-sm font-bold tracking-tight"
                >
                  {t('backToChats')}
                </button>
              </div>
            </div>
          </div>
        ) : activeTab === 'settings' ? (
          <SettingsPage />
        ) : (
          <div className="flex-1 flex items-center justify-center">
            <p className="text-zinc-500">{t('comingSoon') || 'Coming soon'}</p>
          </div>
        )}
      </main>


      <CallModal
        key={callSessionId}
        isOpen={callOpen}
        onClose={handleCloseCall}
        targetUser={callTarget}
        callType={callType}
        incoming={incomingCall}
      />
      <GroupCallModal
        key={`gc-${groupCallSessionId}`}
        isOpen={groupCallOpen}
        onClose={handleCloseGroupCall}
        chatId={groupCallChatId}
        chatName={groupCallChatName}
        callType={groupCallType}
      />

      {/* Scheduled message delivery notification */}
      <AnimatePresence>
        {deliveryNotification && (
          <motion.div
            initial={{ opacity: 0, y: -20, scale: 0.95 }}
            animate={{ opacity: 1, y: 0, scale: 1 }}
            exit={{ opacity: 0, y: -20, scale: 0.95 }}
            className="fixed top-6 left-1/2 -translate-x-1/2 z-[9999] px-5 py-3 rounded-2xl bg-surface-secondary shadow-2xl border border-border flex items-center gap-3"
          >
            <div className="w-8 h-8 rounded-full bg-emerald-500/20 flex items-center justify-center flex-shrink-0">
              <Send size={14} className="text-emerald-400" />
            </div>
            <span className="text-sm text-zinc-200">{deliveryNotification}</span>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Incoming Group Call Overlay */}
      <AnimatePresence>
        {incomingGroupCall && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[200] flex items-center justify-center bg-black/80 backdrop-blur-sm"
          >
            <motion.div
              initial={{ scale: 0.9, y: 20 }}
              animate={{ scale: 1, y: 0 }}
              exit={{ scale: 0.9, y: 20 }}
              className="bg-zinc-900 border border-white/10 p-8 rounded-3xl w-full max-w-sm flex flex-col items-center shadow-2xl"
            >
              <div className="relative mb-6">
                <div className="absolute inset-0 rounded-[1.5rem] bg-emerald-500/20 animate-call-wave" />
                <Avatar
                  src={incomingGroupCall.callerInfo?.avatar ? getMediaUrl(incomingGroupCall.callerInfo.avatar) : null}
                  name={incomingGroupCall.chatName || '?'}
                  size="2xl"
                  className="relative shadow-2xl"
                />
              </div>
              <h2 className="text-2xl text-white font-semibold mb-2 text-center break-words w-full max-w-full">
                {incomingGroupCall.chatName}
              </h2>
              <p className="text-emerald-400 font-medium mb-1 truncate w-full text-center">
                {incomingGroupCall.callerInfo?.displayName || incomingGroupCall.callerInfo?.username || 'User'} {t('isCalling' as any) || 'звонит...'}
              </p>
              <p className="text-zinc-400 text-sm mb-8 bg-white/5 px-3 py-1 rounded-full border border-white/5">
                {t('groupCall' as any) || 'Групповой звонок'}
              </p>

              <div className="flex items-center gap-8 w-full justify-center">
                <button
                  onClick={() => {
                    stopCallRingtone();
                    setIncomingGroupCall(null);
                  }}
                  className="w-16 h-16 rounded-full bg-red-500 hover:bg-red-600 flex items-center justify-center text-white transition-colors shadow-lg shadow-red-500/20"
                >
                  <PhoneOff size={28} />
                </button>
                <button
                  onClick={() => {
                    stopCallRingtone();
                    handleStartGroupCall(incomingGroupCall.chatId, incomingGroupCall.chatName, incomingGroupCall.callType as any);
                    setIncomingGroupCall(null);
                  }}
                  className="w-16 h-16 rounded-full bg-emerald-500 hover:bg-emerald-600 flex items-center justify-center text-white transition-colors animate-pulse shadow-lg shadow-emerald-500/20"
                >
                  <Phone size={28} className="animate-wiggle" />
                </button>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </motion.div>
  );
}
