import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import axios from 'axios';

interface PaginationData {
  current_page: number;
  last_page: number;
  per_page: number;
  total: number;
  from?: number;
  to?: number;
}

interface UseInfinitePuntosProps {
  initialPuntos: unknown[];
  initialPagination: PaginationData;
  filters?: Record<string, string>;
}

export const useInfinitePuntos = ({
  initialPuntos,
  initialPagination,
  filters = {},
}: UseInfinitePuntosProps) => {
  const [puntos, setPuntos] = useState(initialPuntos);
  const [pagination, setPagination] = useState(initialPagination);
  const [isLoading, setIsLoading] = useState(false);
  const [hasMore, setHasMore] = useState(
    initialPagination.current_page < initialPagination.last_page,
  );

  const sentinelRef = useRef<HTMLDivElement | null>(null);
  const loadingRef = useRef(false);
  const listGenerationRef = useRef(0);
  const inertiaPropsRef = useRef({ initialPuntos, initialPagination });
  inertiaPropsRef.current = { initialPuntos, initialPagination };

  const serverListFingerprint = useMemo(
    () =>
      [
        initialPagination.total,
        initialPagination.current_page,
        initialPagination.last_page,
        initialPagination.per_page,
        ...(initialPuntos || []).map((p: { CodPunSum?: number | string }) => String(p?.CodPunSum ?? '')),
      ].join('|'),
    [initialPuntos, initialPagination],
  );

  useEffect(() => {
    listGenerationRef.current += 1;
    const { initialPuntos: ip, initialPagination: pag } = inertiaPropsRef.current;
    setPuntos(ip);
    setPagination(pag);
    setHasMore(pag.current_page < pag.last_page);
    loadingRef.current = false;
  }, [serverListFingerprint]);

  const loadMore = useCallback(async () => {
    if (loadingRef.current || !hasMore) {
      return;
    }

    const generationAtStart = listGenerationRef.current;
    loadingRef.current = true;
    setIsLoading(true);

    try {
      const response = await axios.get(route('puntos-suministro.load-more'), {
        params: {
          page: pagination.current_page + 1,
          per_page: pagination.per_page,
          ...filters,
        },
      });

      if (generationAtStart !== listGenerationRef.current) {
        return;
      }

      const newData = response.data;

      setPuntos((prev) => [...prev, ...(newData.data || [])]);
      setPagination({
        current_page: newData.current_page,
        last_page: newData.last_page,
        per_page: newData.per_page,
        total: newData.total,
        from: newData.from,
        to: newData.to,
      });
      setHasMore(newData.current_page < newData.last_page);
    } catch (error) {
      if ((error as { code?: string })?.code !== 'ERR_CANCELED') {
        console.error('Error cargando más puntos:', error);
      }
    } finally {
      setIsLoading(false);
      loadingRef.current = false;
    }
  }, [pagination.current_page, pagination.per_page, hasMore, filters]);

  const resetWithFilters = useCallback(
    async (newFilters: Record<string, string>) => {
      const generationAtStart = listGenerationRef.current;
      setIsLoading(true);

      try {
        const response = await axios.get(route('puntos-suministro.load-more'), {
          params: {
            page: 1,
            per_page: pagination.per_page,
            ...newFilters,
          },
        });

        if (generationAtStart !== listGenerationRef.current) {
          return;
        }

        const newData = response.data;

        setPuntos(newData.data || []);
        setPagination({
          current_page: newData.current_page,
          last_page: newData.last_page,
          per_page: newData.per_page,
          total: newData.total,
          from: newData.from,
          to: newData.to,
        });
        setHasMore(newData.current_page < newData.last_page);
      } catch (error) {
        if ((error as { code?: string })?.code !== 'ERR_CANCELED') {
          console.error('Error filtrando puntos:', error);
        }
      } finally {
        setIsLoading(false);
      }
    },
    [pagination.per_page],
  );

  useEffect(() => {
    const el = sentinelRef.current;
    if (!el) {
      return undefined;
    }

    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && hasMore && !isLoading) {
          loadMore();
        }
      },
      { rootMargin: '200px' },
    );

    observer.observe(el);

    return () => observer.disconnect();
  }, [hasMore, isLoading, loadMore]);

  return {
    puntos,
    pagination,
    isLoading,
    hasMore,
    loadMore,
    resetWithFilters,
    sentinelRef,
  } as const;
};

export default useInfinitePuntos;
