"use client";

import { AnimatePresence, motion } from "framer-motion";
import { ChevronDown, Search } from "lucide-react";
import {
  Suspense,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { useRouter, useSearchParams } from "next/navigation";

import {
  useGetBlogCategoriesQuery,
  useLazyGetBlogPostsQuery,
} from "@/api/blog.api";
import { IBlogCategory, IBlogPost } from "@/api/types/blog";
import BlogCard from "@/components/Blog/BlogCard";
import BlogCardSkeleton from "@/components/skeleton/BlogCardSkeleton";

function BlogContent() {
  const router = useRouter();
  const searchParams = useSearchParams();

  const categoryIdParam = searchParams.get("categoryId") ?? "";
  const searchParam = searchParams.get("search") ?? "";

  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
  const [searchInput, setSearchInput] = useState(searchParam);
  const [posts, setPosts] = useState<IBlogPost[]>([]);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);
  const [isFetchingMore, setIsFetchingMore] = useState(false);
  const [isInitialLoad, setIsInitialLoad] = useState(true);
  const observerRef = useRef<IntersectionObserver | null>(null);
  const sentinelRef = useRef<HTMLDivElement | null>(null);
  const scrollStateRef = useRef({
    hasMore: true,
    isFetching: false,
    page: 1,
    categoryIdParam: "",
    searchParam: "",
  });

  const { data: categoriesData } = useGetBlogCategoriesQuery();
  const [fetchPosts] = useLazyGetBlogPostsQuery();

  const selectedCategory = useMemo(
    () =>
      categoriesData?.find((c) => c.id.toString() === categoryIdParam) ?? null,
    [categoriesData, categoryIdParam],
  );

  const updateUrl = useCallback(
    (categoryId: string, search: string) => {
      const params = new URLSearchParams();
      if (categoryId) params.set("categoryId", categoryId);
      if (search) params.set("search", search);
      const qs = params.toString();
      router.replace(qs ? `/blog?${qs}` : "/blog", { scroll: false });
    },
    [router],
  );

  // On a hard reload, strip any search/category params so the page starts fresh.
  // Normal navigation (direct links, category clicks) keeps its params.
  useEffect(() => {
    const [nav] = performance.getEntriesByType(
      "navigation",
    ) as PerformanceNavigationTiming[];
    if (nav?.type === "reload" && window.location.search) {
      setSearchInput("");
      router.replace("/blog", { scroll: false });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Debounce search input → push to URL (skip initial mount)
  const isMounted = useRef(false);
  useEffect(() => {
    if (!isMounted.current) { isMounted.current = true; return; }
    const timer = setTimeout(
      () => updateUrl(categoryIdParam, searchInput),
      400,
    );
    return () => clearTimeout(timer);
  }, [searchInput, categoryIdParam, updateUrl]);

  const loadPosts = useCallback(
    async (
      pageNum: number,
      categoryId?: number,
      searchText?: string,
      reset = false,
    ) => {
      scrollStateRef.current.isFetching = true;
      setIsFetchingMore(true);
      try {
        const result = await fetchPosts({
          page: pageNum,
          categoryId,
          searchText,
        });
        if (result.data) {
          const { data, totalPages } = result.data;
          setPosts((prev) => (reset ? data : [...prev, ...data]));
          const more = pageNum < totalPages;
          setHasMore(more);
          scrollStateRef.current.hasMore = more;
          scrollStateRef.current.page = pageNum;
        } else {
          // Error (5xx/4xx) or empty response — stop infinite scroll
          setHasMore(false);
          scrollStateRef.current.hasMore = false;
        }
      } catch {
        setHasMore(false);
        scrollStateRef.current.hasMore = false;
      } finally {
        scrollStateRef.current.isFetching = false;
        setIsFetchingMore(false);
        setIsInitialLoad(false);
      }
    },
    [fetchPosts],
  );

  // Reset + reload whenever URL filter params change
  useEffect(() => {
    const categoryId = categoryIdParam
      ? parseInt(categoryIdParam, 10)
      : undefined;
    scrollStateRef.current = {
      hasMore: true,
      isFetching: false,
      page: 1,
      categoryIdParam,
      searchParam,
    };
    setPosts([]);
    setPage(1);
    setHasMore(true);
    setIsInitialLoad(true);
    loadPosts(1, categoryId, searchParam || undefined, true);
  }, [categoryIdParam, searchParam]); // eslint-disable-line react-hooks/exhaustive-deps

  // Observer created once — reads fresh state via ref to avoid re-creation on filter change
  useEffect(() => {
    if (observerRef.current) observerRef.current.disconnect();

    observerRef.current = new IntersectionObserver(
      (entries) => {
        const { hasMore, isFetching, page, categoryIdParam, searchParam } =
          scrollStateRef.current;
        if (entries[0].isIntersecting && hasMore && !isFetching) {
          const nextPage = page + 1;
          scrollStateRef.current.page = nextPage;
          setPage(nextPage);
          const categoryId = categoryIdParam
            ? parseInt(categoryIdParam, 10)
            : undefined;
          loadPosts(nextPage, categoryId, searchParam || undefined);
        }
      },
      { threshold: 0.1 },
    );

    if (sentinelRef.current) observerRef.current.observe(sentinelRef.current);
    return () => observerRef.current?.disconnect();
  }, [loadPosts]);

  const selectedLabel = selectedCategory?.name ?? "Everything";

  return (
    <div className="min-h-[80vh] lg:min-h-screen bg-white">
      {/* Hero */}
      <div className="flex flex-col items-center text-center pt-8 sm:pt-10 pb-6 sm:pb-8 px-4 sm:px-6">
        <h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold text-[#111827] mb-5 sm:mb-6 leading-tight">
          Seafarer's Favourite blog
        </h1>

        {/* Search */}
        <div className="relative mb-4 w-full max-w-full sm:max-w-130">
          <Search className="absolute left-4 top-1/2 -translate-y-1/2 h-4 w-4 text-[#9ca3af] pointer-events-none" />
          <input
            type="text"
            placeholder="Search Blog"
            value={searchInput}
            onChange={(e) => setSearchInput(e.target.value)}
            className="w-full h-11 text-sm border border-[#e5e7eb] rounded-xl pl-11 pr-4 bg-white focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent placeholder:text-[#9ca3af] transition shadow-sm"
          />
        </div>

        {/* Filter */}
        <div className="flex flex-col xs:flex-row items-center gap-2 xs:gap-3 w-full xs:w-auto">
          <span className="text-sm text-[#6b7280] font-medium whitespace-nowrap ">Filter by topic:</span>
          <div className="relative w-full sm:w-auto">
            <button
              type="button"
              onClick={() => setIsDropdownOpen(!isDropdownOpen)}
              className="flex items-center justify-between gap-2 min-w-[220px] w-full sm:min-w-55 h-9.75 px-5 bg-white border border-[#e5e7eb] rounded-xl text-sm text-[#374151] hover:border-[#d1d5db] transition-colors"
            >
              <span className="font-medium">{selectedLabel}</span>
              <ChevronDown
                className={`h-4 w-4 text-[#9ca3af] transition-transform duration-200 ${isDropdownOpen ? "rotate-180" : ""}`}
              />
            </button>

            <AnimatePresence>
              {isDropdownOpen && (
                <motion.div
                  initial={{ opacity: 0, y: -8 }}
                  animate={{ opacity: 1, y: 0 }}
                  exit={{ opacity: 0, y: -8 }}
                  transition={{ duration: 0.15, ease: "easeOut" }}
                  className="absolute left-0 top-full mt-1 w-full min-w-44 bg-white border border-[#e5e7eb] rounded-xl shadow-lg z-50 overflow-hidden"
                >
                  <button
                    className={`w-full text-left px-5 py-2.5 text-sm transition-colors block cursor-pointer ${
                      !categoryIdParam
                        ? "bg-blue-50 text-[#2563eb] font-medium"
                        : "text-[#374151] hover:bg-[#f9fafb]"
                    }`}
                    onClick={() => {
                      updateUrl("", searchInput);
                      setIsDropdownOpen(false);
                    }}
                  >
                    Everything
                  </button>
                  {(categoriesData ?? []).map((cat) => (
                    <button
                      key={cat.id}
                      className={`w-full text-left px-5 py-2.5 text-sm transition-colors block cursor-pointer ${
                        categoryIdParam === cat.id.toString()
                          ? "bg-blue-50 text-[#2563eb] font-medium"
                          : "text-[#374151] hover:bg-[#f9fafb]"
                      }`}
                      onClick={() => {
                        updateUrl(cat.id.toString(), searchInput);
                        setIsDropdownOpen(false);
                      }}
                    >
                      {cat.name}
                    </button>
                  ))}
                </motion.div>
              )}
            </AnimatePresence>
          </div>
        </div>
      </div>

      {/* Cards */}
      <div className="px-4 sm:px-6 lg:px-0 pb-10 max-w-302.5 mx-auto">
        {isInitialLoad ? (
          <div className="flex flex-wrap gap-5 justify-center">
            {Array.from({ length: 6 }).map((_, i) => (
              <BlogCardSkeleton key={i} />
            ))}
          </div>
        ) : posts.length === 0 ? (
          <div className="bg-white rounded-2xl px-6 py-16 text-center">
            <p className="text-sm text-[#9ca3af]">No blogs match your search.</p>
          </div>
        ) : (
          <div className="flex flex-wrap gap-5 justify-center xl:justify-start">
            {posts.map((post) => <BlogCard key={post.id} post={post} />)}
          </div>
        )}

        {!isInitialLoad && isFetchingMore && (
          <div className="flex flex-wrap gap-5 justify-center lg:justify-start mt-5">
            {Array.from({ length: 3 }).map((_, i) => (
              <BlogCardSkeleton key={i} />
            ))}
          </div>
        )}

        <div ref={sentinelRef} className="h-4 mt-4" />
      </div>
    </div>
  );
}

export default function BlogPage() {
  return (
    <Suspense>
      <BlogContent />
    </Suspense>
  );
}
