"use client";

import { useState, useEffect, useRef, useCallback } from "react";
import EscortCard from "./escort-card";

interface Escort {
  id: number;
  id_aw: string | null;
  username: string | null;
  profile_photo: string | null;
  is_verified: boolean;
  is_vip: boolean;
  status: string | null;
  lastonline_at: Date | null;
  is_agency?: boolean | null;
  country?: { name: string } | null;
  city?: { name: string } | null;
  photo_count?: number;
  avatarMediaUrls?: string[];
}

interface InfiniteEscortGridProps {
  initialEscorts: Escort[];
  initialHasMore?: boolean;
  sort: string;
  countryId?: number;
  cityId?: number;
}

export default function InfiniteEscortGrid({
  initialEscorts,
  initialHasMore = initialEscorts.length >= 48,
  sort,
  countryId,
  cityId,
}: InfiniteEscortGridProps) {
  const [escorts, setEscorts] = useState<Escort[]>(initialEscorts);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);
  const [hasMore, setHasMore] = useState(initialHasMore);
  const sentinelRef = useRef<HTMLDivElement>(null);

  // Reset client state when the parent server component re-renders with a
  // new initialEscorts batch (e.g. user changed the sort dropdown). Without
  // this, stale client-paginated rows stay appended below the new server
  // snapshot.
  useEffect(() => {
    setEscorts(initialEscorts);
    setPage(1);
    setHasMore(initialHasMore);
  }, [initialEscorts, initialHasMore]);

  const loadMore = useCallback(async () => {
    if (loading || !hasMore) return;
    setLoading(true);
    try {
      const params = new URLSearchParams({
        page: String(page + 1),
        sort,
        ...(countryId ? { countryId: String(countryId) } : {}),
        ...(cityId ? { cityId: String(cityId) } : {}),
      });
      const res = await fetch(`/api/escorts?${params}`);
      if (res.ok) {
        const data = await res.json();
        const newEscorts: Escort[] = data.escorts ?? [];
        setPage((p) => p + 1);
        setHasMore(data.hasMore === true);
        if (newEscorts.length > 0) {
          setEscorts((prev) => [...prev, ...newEscorts]);
        }
      }
    } catch {
      // silently fail
    } finally {
      setLoading(false);
    }
  }, [loading, hasMore, page, sort, countryId, cityId]);

  useEffect(() => {
    const sentinel = sentinelRef.current;
    if (!sentinel) return;

    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0]?.isIntersecting) {
          loadMore();
        }
      },
      { rootMargin: "200px" }
    );

    observer.observe(sentinel);
    return () => observer.disconnect();
  }, [loadMore]);

  return (
    <>
      <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4">
        {escorts.map((escort) => (
          <EscortCard key={escort.id} escort={escort} />
        ))}
      </div>

      {/* Sentinel for infinite scroll */}
      <div ref={sentinelRef} className="h-1" />

      {loading && (
        <div className="flex justify-center py-8">
          <div className="h-8 w-8 border-2 border-primary border-t-transparent rounded-full animate-spin" />
        </div>
      )}

      {!hasMore && escorts.length > 0 && (
        <p className="text-center text-text-muted text-sm py-6">
          You&apos;ve seen all results
        </p>
      )}
    </>
  );
}
