import { useEffect, useRef, useState, useCallback } from 'react';
import { supabase } from '../lib/supabase';
import type { RealtimeChannel } from '@supabase/supabase-js';

/**
 * Typing-Indicator für eine DM-Konversation via Supabase-Broadcast (ephemer,
 * KEIN DB-Write — Tipp-Status muss nicht persistiert werden).
 *
 * Beide Peers joinen denselben deterministischen Channel (sortiertes ID-Paar),
 * damit `send()` von A bei B ankommt. `self:false` filtert die eigenen Events.
 *
 * STABILITÄT (gegen Flackern Online⇄tippt):
 * Der Sender feuert nicht nur bei Tastendruck, sondern hält einen HEARTBEAT
 * (alle HEARTBEAT_MS), solange aktiv komponiert wird (Feld fokussiert + Text
 * vorhanden). Sonst würde bei jeder Denkpause der Empfänger-Auto-Clear greifen
 * und der Status auf „Online" zurückspringen. Der Clear-Timeout liegt deutlich
 * über dem Heartbeat, damit ein einzelnes verlorenes Broadcast nicht flackert.
 *
 *  - `setComposing(true|false)` → startet/stoppt Heartbeat (true = aktiv tippen)
 *  - `sendStopTyping()`         → sofortiger „Stop" (beim Senden / Blur / Leeren)
 *  - `partnerTyping`            → true solange Partner-Heartbeats reinkommen
 */
const HEARTBEAT_MS = 2000;
const CLEAR_MS = 6000; // > HEARTBEAT_MS, toleriert ~2 verlorene Beats

export function useDmTyping(myUserId: string | undefined, partnerId: string | undefined) {
  const [partnerTyping, setPartnerTyping] = useState(false);
  const channelRef = useRef<RealtimeChannel | null>(null);
  const clearTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const heartbeat = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    if (!myUserId || !partnerId) return;
    const pair = [myUserId, partnerId].sort().join('_');
    const channel = supabase.channel(`dm-typing:${pair}`, {
      config: { broadcast: { self: false } },
    });
    channel
      .on('broadcast', { event: 'typing' }, (msg: any) => {
        if (msg?.payload?.userId !== partnerId) return;
        setPartnerTyping(true);
        if (clearTimer.current) clearTimeout(clearTimer.current);
        clearTimer.current = setTimeout(() => setPartnerTyping(false), CLEAR_MS);
      })
      .on('broadcast', { event: 'stop_typing' }, (msg: any) => {
        if (msg?.payload?.userId !== partnerId) return;
        if (clearTimer.current) clearTimeout(clearTimer.current);
        setPartnerTyping(false);
      })
      .subscribe();
    channelRef.current = channel;

    return () => {
      if (clearTimer.current) clearTimeout(clearTimer.current);
      if (heartbeat.current) clearInterval(heartbeat.current);
      heartbeat.current = null;
      supabase.removeChannel(channel);
      channelRef.current = null;
      setPartnerTyping(false);
    };
  }, [myUserId, partnerId]);

  const broadcast = useCallback(
    (event: 'typing' | 'stop_typing') => {
      channelRef.current?.send({ type: 'broadcast', event, payload: { userId: myUserId } });
    },
    [myUserId],
  );

  const sendStopTyping = useCallback(() => {
    if (heartbeat.current) {
      clearInterval(heartbeat.current);
      heartbeat.current = null;
    }
    broadcast('stop_typing');
  }, [broadcast]);

  /**
   * Aktiv-Status setzen. true = der lokale User komponiert gerade (Feld
   * fokussiert + Text vorhanden) → Heartbeat läuft. false = aufhören.
   */
  const setComposing = useCallback(
    (active: boolean) => {
      if (active) {
        if (heartbeat.current) return; // Heartbeat läuft bereits
        broadcast('typing'); // sofort sichtbar, nicht erst nach 2s
        heartbeat.current = setInterval(() => broadcast('typing'), HEARTBEAT_MS);
      } else {
        if (heartbeat.current) {
          clearInterval(heartbeat.current);
          heartbeat.current = null;
        }
        broadcast('stop_typing');
      }
    },
    [broadcast],
  );

  return { partnerTyping, setComposing, sendStopTyping };
}
