'use client';
import { createContext, useContext, useState, useCallback, useEffect, useTransition } from 'react';
import { useRouter } from 'next/navigation';
import type { User } from '@/lib/auth';
import type { Notif } from '@/lib/queries';
import { toggleFavorite, logout as logoutAction, markNotificationsRead } from '@/lib/actions';

type AuthCtx = {
  user: User | null;
  isFav: (kind: 'biz' | 'ad', id: number) => boolean;
  toggleFav: (kind: 'biz' | 'ad', id: number) => void;
  logout: () => void;
  notifications: Notif[];
  notifUnread: number;
  markNotifsRead: () => void;
};

const Ctx = createContext<AuthCtx>({
  user: null,
  isFav: () => false,
  toggleFav: () => {},
  logout: () => {},
  notifications: [],
  notifUnread: 0,
  markNotifsRead: () => {},
});

export function useAuth() {
  return useContext(Ctx);
}

export function AuthProvider({
  user,
  favorites,
  notifications = [],
  notifUnread = 0,
  children,
}: {
  user: User | null;
  favorites: string[];
  notifications?: Notif[];
  notifUnread?: number;
  children: React.ReactNode;
}) {
  const router = useRouter();
  const [favs, setFavs] = useState<Set<string>>(new Set(favorites));
  const [unread, setUnread] = useState(notifUnread);
  const [, startTransition] = useTransition();

  useEffect(() => setFavs(new Set(favorites)), [favorites]);
  useEffect(() => setUnread(notifUnread), [notifUnread]);

  // One global real-time stream: refresh server data (messages + notifications + bell) on any
  // event. Falls back to polling if SSE is unavailable or buffered (e.g. behind Passenger/Apache
  // on shared hosting like o2switch).
  useEffect(() => {
    if (!user) return;
    let opened = false;
    let pollId: ReturnType<typeof setInterval> | null = null;
    const startPolling = () => {
      if (!pollId) pollId = setInterval(() => router.refresh(), 15000);
    };
    const stopPolling = () => {
      if (pollId) {
        clearInterval(pollId);
        pollId = null;
      }
    };
    let es: EventSource | null = null;
    try {
      es = new EventSource('/api/stream');
      es.onopen = () => {
        opened = true;
        stopPolling();
      };
      es.onmessage = (e) => {
        if (e.data === 'inbox') router.refresh();
      };
      es.onerror = () => startPolling();
    } catch {
      startPolling();
    }
    const t = setTimeout(() => {
      if (!opened) startPolling();
    }, 6000);
    return () => {
      clearTimeout(t);
      stopPolling();
      es && es.close();
    };
  }, [user, router]);

  const isFav = useCallback((kind: 'biz' | 'ad', id: number) => favs.has(`${kind}:${id}`), [favs]);

  const toggleFav = useCallback(
    (kind: 'biz' | 'ad', id: number) => {
      if (!user) {
        router.push('/connexion');
        return;
      }
      const key = `${kind}:${id}`;
      setFavs((s) => {
        const n = new Set(s);
        n.has(key) ? n.delete(key) : n.add(key);
        return n;
      });
      startTransition(() => {
        toggleFavorite(kind, id);
      });
    },
    [user, router]
  );

  const logout = useCallback(() => {
    startTransition(() => {
      logoutAction();
    });
  }, []);

  const markNotifsRead = useCallback(() => {
    if (unread === 0) return;
    setUnread(0);
    startTransition(async () => {
      await markNotificationsRead();
      router.refresh();
    });
  }, [unread, router]);

  return (
    <Ctx.Provider
      value={{ user, isFav, toggleFav, logout, notifications, notifUnread: unread, markNotifsRead }}
    >
      {children}
    </Ctx.Provider>
  );
}
