import { useEffect, useRef } from 'react';
import { useInAppNotificationStore } from '../stores/inAppNotificationStore';
import { AudioManager } from '../audio/AudioManager';
import { getSfxVolume } from '../utils/sfx';
import { translate, useLocaleStore } from '../i18n';
import { useChatStore } from '../stores/chatStore';
import { useVoiceStore } from '../stores/voiceStore';
import { useAuthStore } from '../stores/authStore';
import { isElectron } from '../platform/platform';
import { sendNotification, updateBadgeCount } from '../platform/notifications';

/**
 * Headless component that bridges store events to native OS notifications and badge counts.
 * Renders nothing — lives alongside SoundController in AppLayout.
 */
export function NotificationController() {
  const currentUser = useAuthStore((s) => s.user);
  const isInitialMount = useRef(true);
  const windowFocused = useRef(true);

  // Track window focus state
  useEffect(() => {
    if (isElectron() && window.backspace) {
      window.backspace.onWindowFocusChange((focused) => {
        windowFocused.current = focused;
      });
    }

    // Browser fallback focus tracking
    const onFocus = () => { windowFocused.current = true; };
    const onBlur = () => { windowFocused.current = false; };
    const onVisibility = () => {
      windowFocused.current = document.visibilityState === 'visible' && document.hasFocus();
    };

    window.addEventListener('focus', onFocus);
    window.addEventListener('blur', onBlur);
    document.addEventListener('visibilitychange', onVisibility);

    // Sync initial state
    windowFocused.current = document.hasFocus();

    return () => {
      window.removeEventListener('focus', onFocus);
      window.removeEventListener('blur', onBlur);
      document.removeEventListener('visibilitychange', onVisibility);
    };
  }, []);

  // Message notifications
  useEffect(() => {
    const timer = setTimeout(() => {
      isInitialMount.current = false;
    }, 1000);

    const unsubscribeChat = useChatStore.subscribe((state, prevState) => {
      if (isInitialMount.current) return;
      // Antes daqui só havia aviso com a janela fora de foco. Agora a janela em
      // foco também avisa, mas dentro do app e apenas para outro canal — avisar
      // sobre a conversa que a pessoa está lendo seria ruído.
      const focused = windowFocused.current;
      const currentChannel = state.currentChannelId;

      if (state.realtimeMessageEvents.length > prevState.realtimeMessageEvents.length) {
        const newEvents = state.realtimeMessageEvents.slice(prevState.realtimeMessageEvents.length);
        for (const { message } of newEvents) {
          if (message.userId !== currentUser?.id) {
            if (focused && message.channelId === currentChannel) break;

            const displayName = message.user?.displayName || message.user?.username || 'Someone';
            const body = message.content
              ? message.content.replace(/[*_~`>#\-\[\]]/g, '').slice(0, 100)
              : translate(useLocaleStore.getState().locale, 'notify.attachment');

            useInAppNotificationStore.getState().push({
              title: displayName,
              body,
              avatar: message.user?.avatar ?? null,
              userId: message.user?.id,
              channelId: message.channelId,
            });
            // Efeito próprio, no lugar do som do sistema. O balão nativo agora
            // é silencioso, então este é o único som que toca.
            void AudioManager.getInstance().playSound('notification', { volume: getSfxVolume() });

            // O balão do sistema só faz sentido quando a janela não está à
            // vista: com ela em foco, o aviso dentro do app já cumpre o papel.
            if (!focused) {
              sendNotification(displayName, body, { channelId: message.channelId });
            }
            break; // one notification per batch
          }
        }
      }
    });

    return () => {
      clearTimeout(timer);
      unsubscribeChat();
    };
  }, [currentUser?.id]);

  // Badge count (Electron only)
  useEffect(() => {
    const unsubscribe = useChatStore.subscribe((state) => {
      updateBadgeCount(state.unreadChannels.size);
    });
    return unsubscribe;
  }, []);

  // DM call notification
  useEffect(() => {
    let prevIncoming: { dmChannelId: string | null; callerId: string; callerName: string } | null = null;

    const unsubscribe = useVoiceStore.subscribe((state) => {
      if (state.incomingCall && !prevIncoming && !windowFocused.current) {
        sendNotification('Incoming Call', `${state.incomingCall.callerName} is calling you`);
      }
      prevIncoming = state.incomingCall;
    });
    return unsubscribe;
  }, []);

  return null;
}
