import { useCallback, useEffect, useRef, useState } from 'react';
import type { LocaleCode } from '../i18n/messages';

type Photo = {
  id: number;
  file_path?: string;
  thumbnail_path?: string;
  created_at?: string;
  session_id?: string | null;
  uploader_name?: string | null;
};
type RawPhoto = Record<string, unknown>;

export function usePollGalleryDelta(token: string, locale: LocaleCode) {
  const [photos, setPhotos] = useState<Photo[]>([]);
  const [loading, setLoading] = useState(true);
  const [newCount, setNewCount] = useState(0);
  const latestAt = useRef<string | null>(null);
  const etagRef = useRef<string | null>(null);
  const timer = useRef<number | null>(null);
  const [visible, setVisible] = useState(
    typeof document !== 'undefined' ? document.visibilityState === 'visible' : true
  );

  const fetchDelta = useCallback(async () => {
    if (!token) {
      setLoading(false);
      return;
    }

    try {
      const params = new URLSearchParams();
      if (latestAt.current) {
        params.set('since', latestAt.current);
      }
      params.set('locale', locale);

      const headers: HeadersInit = {
        'Cache-Control': 'no-store',
        'X-Locale': locale,
        'Accept': 'application/json',
      };

      if (etagRef.current) {
        headers['If-None-Match'] = etagRef.current;
      }

      const res = await fetch(`/api/v1/events/${encodeURIComponent(token)}/photos?${params.toString()}`, {
        headers,
      });
      
      if (res.status === 304) return; // No new content
      
      if (!res.ok) {
        console.warn(`Gallery API error: ${res.status} ${res.statusText}`);
        return; // Don't update state on error
      }
      
      const json = await res.json();
      etagRef.current = res.headers.get('ETag');
      
      // Handle different response formats
      const rawPhotos = Array.isArray(json.data) ? json.data :
                       Array.isArray(json) ? json :
                       json.photos || [];

      const newPhotos: Photo[] = rawPhotos.map((photo: RawPhoto) => ({
        ...(photo as Photo),
        session_id: typeof photo.session_id === 'string' ? photo.session_id : (photo.guest_name as string | null) ?? null,
        uploader_name:
          typeof photo.uploader_name === 'string'
            ? (photo.uploader_name as string)
            : typeof photo.guest_name === 'string'
              ? (photo.guest_name as string)
              : null,
      }));
      
      if (newPhotos.length > 0) {
        const added = newPhotos.length;
        const hasBaseline = latestAt.current !== null;

        setPhotos((prev) => {
          if (hasBaseline) {
            // Delta mode: merge new photos with existing list by id
            const merged = [...newPhotos, ...prev];
            const byId = new Map<number, Photo>();
            merged.forEach((photo) => byId.set(photo.id, photo));
            return Array.from(byId.values());
          }

          return newPhotos;
        });

        if (hasBaseline && added > 0) {
          setNewCount((c) => c + added);
        }
        
        // Update latest timestamp
        if (json.latest_photo_at) {
          latestAt.current = json.latest_photo_at;
        } else if (newPhotos.length > 0) {
          // Fallback: use newest photo timestamp
          const newest = newPhotos.reduce((latest: number, photo: RawPhoto) => {
            const photoTime = new Date((photo.created_at as string | undefined) || (photo.created_at_timestamp as number | undefined) || 0).getTime();
            return photoTime > latest ? photoTime : latest;
          }, 0);
          latestAt.current = new Date(newest).toISOString();
        }
      } else if (latestAt.current) {
        // Delta mode but no new photos: keep existing photos
        console.log('No new photos, keeping existing gallery state');
        // Don't update photos state
      } else {
        // Initial load with no photos
        setPhotos([]);
      }
      
      setLoading(false);
    } catch (error) {
      console.error('Gallery polling error:', error);
      setLoading(false);
      // Don't update state on error - keep previous photos
    }
  }, [locale, token]);

  useEffect(() => {
    const onVis = () => setVisible(document.visibilityState === 'visible');
    document.addEventListener('visibilitychange', onVis);
    return () => document.removeEventListener('visibilitychange', onVis);
  }, []);

  useEffect(() => {
    if (!token) {
      setPhotos([]);
      setLoading(false);
      return;
    }

    setLoading(true);
    latestAt.current = null;
    etagRef.current = null;
    setPhotos([]);
    void fetchDelta();
    if (timer.current) window.clearInterval(timer.current);
    // Poll less aggressively when hidden
    const interval = visible ? 30_000 : 90_000;
    timer.current = window.setInterval(() => { void fetchDelta(); }, interval);
    return () => {
      if (timer.current) window.clearInterval(timer.current);
    };
  }, [token, visible, locale, fetchDelta]);

  const refreshNow = useCallback(async () => {
    if (!token) {
      return;
    }
    setLoading(true);
    latestAt.current = null;
    etagRef.current = null;
    setNewCount(0);
    setPhotos([]);
    await fetchDelta();
  }, [fetchDelta, token]);

  function acknowledgeNew() { setNewCount(0); }
  return { loading, photos, newCount, acknowledgeNew, refreshNow };
}
