"use client";

import React, { useEffect, useLayoutEffect, useRef, useState, useCallback, useMemo } from "react";
import { useRouter, usePathname } from "next/navigation";
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
import { fetchPosts } from "@/api/fetchPosts";
import { fetchPostById } from "@/api/fetchPostById";
import { Post } from "@/types/types";
import { MutedProvider } from "@/components/models/ModelPage/MainModelCardPost";
import PageLoader from "@/components/ui/PageLoader";
import Cookies from "js-cookie";
import ReelsPostCard, { VideoPreloadPriority } from "./ReelsPostCard";
import ReelsTabBar, { parseReelsTab, ReelsTab } from "./ReelsTabBar";
import FollowingSuggestionsCarousel, {
  SuggestedFollowUser,
} from "./FollowingSuggestionsCarousel";
import { normalizeUserLevel } from "@/lib/userLevel";
import { readReelsSeedPost } from "@/lib/reelsSeedPost";
import { prefetchPostVideo, prefetchPostVideos } from "@/lib/videoPreload";
import { reorderColdStartFeed } from "@/lib/coldStartFeed";
import {
  postMatchesReelsMediaType,
  resolveReelsMediaType,
} from "@/lib/reelsMediaType";
import { buildExplorePostFilters } from "@/lib/explore/buildPostFilters";
import { ExploreFilterId } from "@/constants/exploreFilters";
import { isPublicPostStatus } from "@/lib/moderationStatus";
import { useReelsSnapScroll, REELS_SCROLL_CLASS, getReelsStepHeight } from "@/hooks/useReelsSnapScroll";
import ReelsScrollSlot from "./ReelsScrollSlot";
import { ExploreReelsUiProvider } from "@/contexts/ExploreReelsUiContext";
import {
  REELS_BG_PREFETCH_DELAY_MS,
  REELS_FIRST_PAGE_SIZE,
  REELS_PAGE_SIZE,
  REELS_PREFETCH_AHEAD,
  REELS_SHELL_CLASS,
} from "@/constants/reelsFeed";
import { useTranslation } from "react-i18next";

/** تأخیر قبل از fetch فید اکسپلور — پست کلیک‌شده اول نمایش داده شود */
const EXPLORE_FEED_DELAY_MS = 350;
const PREFETCH_AHEAD = REELS_PREFETCH_AHEAD;

export type PostFeedSearchParams = {
  feed?: string;
  tab?: string;
  userId?: string;
  expertise?: string;
  province?: string;
  city?: string;
  userLevel?: string;
  rateFilter?: string;
  hashtag?: string;
  exploreFilter?: string;
  subExpertise?: string;
  filter?: string;
  lat?: string;
  lng?: string;
  q?: string;
};

interface PostFeedViewProps {
  initialPostId: string;
  initialPost?: Post | null;
  userId?: string;
  showClose?: boolean;
  videoOnly?: boolean;
  exploreMode?: boolean;
  feedMode?: "user" | "home" | "explore";
  /** از سرور — بدون Suspense و useSearchParams */
  searchParams?: PostFeedSearchParams;
}

function pickInstantPost(
  id: string,
  initialPost?: Post | null
): Post | null {
  if (initialPost?._id) return initialPost;
  return readReelsSeedPost(id);
}

export default function PostFeedView({
  initialPostId,
  initialPost: initialPostProp,
  userId: userIdProp,
  showClose = true,
  videoOnly = false,
  exploreMode = false,
  feedMode: feedModeProp,
  searchParams: searchParamsProp = {},
}: PostFeedViewProps) {
  const { t } = useTranslation("common");
  const router = useRouter();
  const pathname = usePathname();
  const queryClient = useQueryClient();
  const token = Cookies.get("token") || "";
  const scrollRef = useRef<HTMLDivElement>(null);
  useReelsSnapScroll(scrollRef);
  const scrolledRef = useRef(false);

  const [seedPost, setSeedPost] = useState<Post | null>(() =>
    pickInstantPost(initialPostId, initialPostProp)
  );
  const instantPost = seedPost || initialPostProp || null;

  const [activePostId, setActivePostId] = useState(initialPostId);
  const [reelsTab, setReelsTab] = useState<ReelsTab>(() =>
    parseReelsTab(searchParamsProp.tab ?? null)
  );
  const [followingSuggestionsDismissed, setFollowingSuggestionsDismissed] =
    useState(false);
  const [feedFetchEnabled, setFeedFetchEnabled] = useState(false);
  const [nearMeCoords, setNearMeCoords] = useState<{
    lat: number;
    lng: number;
  } | null>(null);
  const [nearMeLocationError, setNearMeLocationError] = useState(false);

  const userIdFromQuery = searchParamsProp.userId || "";
  const feedFromQuery = searchParamsProp.feed;
  const isProfileReels = !!(userIdProp || userIdFromQuery);

  const feedMode =
    feedModeProp ||
    (feedFromQuery === "user" || isProfileReels
      ? "user"
      : feedFromQuery === "explore" || exploreMode
        ? "explore"
        : feedFromQuery === "home" || showClose
          ? "home"
          : "user");

  const showReelsTabs =
    (feedMode === "home" || feedMode === "explore") &&
    showClose &&
    !isProfileReels;

  // پست کلیک‌شده فوراً نمایش داده شود؛ فید در پس‌زمینه با تأخیر شروع شود
  useEffect(() => {
    if (!instantPost) {
      setFeedFetchEnabled(true);
      return;
    }

    const delay = feedMode === "explore" ? EXPLORE_FEED_DELAY_MS : 1;
    const timer = window.setTimeout(() => setFeedFetchEnabled(true), delay);
    return () => window.clearTimeout(timer);
  }, [instantPost, feedMode]);

  useLayoutEffect(() => {
    const cached = readReelsSeedPost(initialPostId);
    if (cached) {
      setSeedPost((prev) => prev ?? cached);
      prefetchPostVideo(cached, "high");
    }
  }, [initialPostId]);

  useEffect(() => {
    if (instantPost) prefetchPostVideo(instantPost, "high");
  }, [instantPost?._id]);

  useEffect(() => {
    let cancelled = false;
    scrolledRef.current = false;
    setActivePostId(initialPostId);

    const cached = readReelsSeedPost(initialPostId);
    const next = initialPostProp || cached;
    if (next) setSeedPost(next);

    if (initialPostProp || cached) return;

    fetchPostById(initialPostId, token).then((post) => {
      if (cancelled || !post) return;
      setSeedPost(post);
    });

    return () => {
      cancelled = true;
    };
  }, [initialPostId, initialPostProp, token]);

  const feedFilters = {
    expertise: searchParamsProp.expertise || "",
    province: searchParamsProp.province || "",
    city: searchParamsProp.city || "",
    userLevel: normalizeUserLevel(searchParamsProp.userLevel || ""),
    rateFilter: searchParamsProp.rateFilter || "",
    hashtag: searchParamsProp.hashtag || "",
    exploreFilter: searchParamsProp.exploreFilter || "",
    subExpertise: searchParamsProp.subExpertise || "",
  };

  const [resolvedUserId, setResolvedUserId] = useState(
    userIdProp || userIdFromQuery || ""
  );

  useEffect(() => {
    if (feedMode !== "user") return;
    if (userIdProp || userIdFromQuery) {
      setResolvedUserId(userIdProp || userIdFromQuery);
      return;
    }
    const uid = instantPost?.userId || instantPost?.user_id;
    if (uid) {
      setResolvedUserId(uid);
      return;
    }
    fetchPostById(initialPostId).then((post) => {
      const id = post?.userId || post?.user_id;
      if (id) setResolvedUserId(id);
    });
  }, [
    initialPostId,
    userIdProp,
    userIdFromQuery,
    feedMode,
    instantPost?.user_id,
    instantPost?.userId,
  ]);

  const reelsMediaType =
    feedMode === "user"
      ? undefined
      : resolveReelsMediaType(instantPost, videoOnly);

  const isReelsFeed =
    feedMode === "home" || feedMode === "explore" || feedMode === "user";

  const exploreFilterId =
    (searchParamsProp.filter as ExploreFilterId) || "all";
  const exploreCoords =
    searchParamsProp.lat && searchParamsProp.lng
      ? {
          lat: parseFloat(searchParamsProp.lat),
          lng: parseFloat(searchParamsProp.lng),
        }
      : null;

  const exploreFilters = useMemo(
    () => ({
      ...buildExplorePostFilters(exploreFilterId, exploreCoords),
      ...(searchParamsProp.hashtag ? { hashtag: searchParamsProp.hashtag } : {}),
      ...(searchParamsProp.q ? { q: searchParamsProp.q } : {}),
    }),
    [
      exploreFilterId,
      exploreCoords?.lat,
      exploreCoords?.lng,
      searchParamsProp.hashtag,
      searchParamsProp.q,
    ]
  );

  const queryFilters =
    feedMode === "user"
      ? { ...(resolvedUserId ? { _id: resolvedUserId } : {}) }
      : feedMode === "explore"
        ? reelsTab === "for_you"
          ? Object.fromEntries(
              Object.entries(exploreFilters).filter(([, v]) => v)
            )
          : {}
        : feedMode === "home"
          ? Object.fromEntries(
              Object.entries(feedFilters).filter(([, v]) => v)
            )
          : {};

  useEffect(() => {
    scrolledRef.current = false;
    if (reelsTab === "following") {
      setFollowingSuggestionsDismissed(false);
    }
    if (scrollRef.current) {
      scrollRef.current.scrollTo({ top: 0, behavior: "auto" });
    }
  }, [reelsTab]);

  const apiReelsTab =
    showReelsTabs && reelsTab !== "for_you" ? reelsTab : undefined;

  const nearMeReady = reelsTab !== "near_me" || !!nearMeCoords;

  const canFetchFeed =
    feedFetchEnabled &&
    nearMeReady &&
    (feedMode === "home" ||
      feedMode === "explore" ||
      !!resolvedUserId ||
      !!token) &&
    (!isReelsFeed || !!reelsMediaType || !!instantPost);

  const { data, isLoading, isError, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useInfiniteQuery({
      queryKey: [
        "post-feed",
        feedMode,
        reelsTab,
        resolvedUserId,
        initialPostId,
        reelsMediaType,
        queryFilters,
        nearMeCoords?.lat,
        nearMeCoords?.lng,
      ],
      queryFn: ({ pageParam = 1 }) =>
        fetchPosts(
          pageParam as number,
          pageParam === 1 ? REELS_FIRST_PAGE_SIZE : REELS_PAGE_SIZE,
          {
            ...queryFilters,
            ...(isReelsFeed
              ? {
                  feedMode: "reels" as const,
                  ...(reelsMediaType ? { type: reelsMediaType } : {}),
                  ...(pageParam === 1 &&
                  reelsTab === "for_you" &&
                  (feedMode === "home" || feedMode === "explore")
                    ? { seedPostId: initialPostId }
                    : {}),
                  ...(apiReelsTab ? { reelsTab: apiReelsTab } : {}),
                  ...(reelsTab === "near_me" && nearMeCoords
                    ? {
                        lat: String(nearMeCoords.lat),
                        lng: String(nearMeCoords.lng),
                      }
                    : {}),
                }
              : {}),
          },
          token
        ),
      initialPageParam: 1,
      getNextPageParam: (lastPage, pages) =>
        lastPage.posts?.length ? pages.length + 1 : undefined,
      enabled: canFetchFeed,
    });

  const feedMeta = data?.pages?.[0]?.feedMeta;
  const suggestedUsers = (feedMeta?.suggestedUsers ?? []) as SuggestedFollowUser[];
  const emptyFollowing = !!feedMeta?.emptyFollowing && reelsTab === "following";
  const emptySaved = !!feedMeta?.emptySaved && reelsTab === "saved";
  const emptyNearMe = !!feedMeta?.emptyNearMe && reelsTab === "near_me";
  const needsLocation = !!feedMeta?.needsLocation && reelsTab === "near_me";
  const requiresAuth =
    !!feedMeta?.requiresAuth &&
    (reelsTab === "following" || reelsTab === "saved");

  const feedPosts: Post[] = useMemo(() => {
    if (requiresAuth || emptyFollowing || emptySaved || emptyNearMe || needsLocation) {
      return [];
    }

    const apiPosts =
      data?.pages
        ?.flatMap((p) => p.posts)
        ?.filter(
          (p) =>
            isPublicPostStatus((p as Post).status) &&
            postMatchesReelsMediaType(p as Post, reelsMediaType)
        ) ?? [];

    const restPosts =
      instantPost &&
      reelsTab === "for_you" &&
      (feedMode === "home" || feedMode === "explore") &&
      (data?.pages?.[0]?.feedMeta?.isColdStart ?? !token)
        ? reorderColdStartFeed(apiPosts as Post[], instantPost)
        : (apiPosts as Post[]);

    return restPosts as Post[];
  }, [
    data,
    instantPost,
    reelsMediaType,
    feedMode,
    token,
    reelsTab,
    emptyFollowing,
    emptySaved,
    emptyNearMe,
    needsLocation,
    requiresAuth,
  ]);

  const visiblePosts: Post[] = useMemo(() => {
    if (requiresAuth || emptyFollowing || emptySaved || emptyNearMe || needsLocation) {
      return [];
    }

    const seen = new Set<string>();
    const merged: Post[] = [];

    const addPost = (post: Post) => {
      const id = String(post._id);
      if (seen.has(id)) return;
      if (!isPublicPostStatus(post.status)) return;
      if (!postMatchesReelsMediaType(post, reelsMediaType)) return;
      seen.add(id);
      merged.push(post);
    };

    const includeInstant =
      instantPost &&
      (feedMode === "user" || !showReelsTabs || reelsTab === "for_you");

    if (includeInstant) addPost(instantPost);
    feedPosts.forEach(addPost);

    return merged;
  }, [
    instantPost,
    feedPosts,
    reelsMediaType,
    reelsTab,
    feedMode,
    showReelsTabs,
    emptyFollowing,
    emptySaved,
    emptyNearMe,
    needsLocation,
    requiresAuth,
  ]);

  useEffect(() => {
    if (reelsTab !== "near_me") {
      setNearMeLocationError(false);
      return;
    }

    if (!navigator.geolocation) {
      setNearMeLocationError(true);
      return;
    }

    navigator.geolocation.getCurrentPosition(
      (pos) => {
        setNearMeCoords({
          lat: pos.coords.latitude,
          lng: pos.coords.longitude,
        });
        setNearMeLocationError(false);
      },
      () => {
        setNearMeCoords(null);
        setNearMeLocationError(true);
      },
      { enableHighAccuracy: true, timeout: 12000, maximumAge: 60000 }
    );
  }, [reelsTab]);

  useLayoutEffect(() => {
    if (scrolledRef.current || !visiblePosts.length || !scrollRef.current) {
      return;
    }

    const idx = visiblePosts.findIndex(
      (p) => String(p._id) === String(initialPostId)
    );
    const targetIdx = idx >= 0 ? idx : 0;

    scrollRef.current.scrollTo({
      top: targetIdx * getReelsStepHeight(scrollRef.current),
      behavior: "auto",
    });
    scrolledRef.current = true;
    setActivePostId(visiblePosts[targetIdx]?._id || initialPostId);
  }, [visiblePosts, initialPostId]);

  const handleScroll = useCallback(() => {
    const el = scrollRef.current;
    if (!el || !visiblePosts.length) return;

    const step = getReelsStepHeight(el);
    const index = Math.round(el.scrollTop / step);
    if (
      index >= visiblePosts.length - PREFETCH_AHEAD &&
      hasNextPage &&
      !isFetchingNextPage
    ) {
      fetchNextPage();
    }
  }, [visiblePosts.length, hasNextPage, isFetchingNextPage, fetchNextPage]);

  const syncActivePostFromScroll = useCallback(() => {
    const el = scrollRef.current;
    if (!el || !visiblePosts.length) return;

    const step = el.clientHeight || window.innerHeight;
    const index = Math.min(
      visiblePosts.length - 1,
      Math.max(0, Math.round(el.scrollTop / step))
    );
    const post = visiblePosts[index];
    if (post && String(post._id) !== String(activePostId)) {
      setActivePostId(post._id);
    }
  }, [visiblePosts, activePostId]);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;

    let settleTimer: number | null = null;

    const onScroll = () => {
      handleScroll();
      if (settleTimer) window.clearTimeout(settleTimer);
      settleTimer = window.setTimeout(syncActivePostFromScroll, 80);
    };

    const onScrollEnd = () => {
      if (settleTimer) window.clearTimeout(settleTimer);
      syncActivePostFromScroll();
    };

    el.addEventListener("scroll", onScroll, { passive: true });
    el.addEventListener("scrollend", onScrollEnd);

    return () => {
      el.removeEventListener("scroll", onScroll);
      el.removeEventListener("scrollend", onScrollEnd);
      if (settleTimer) window.clearTimeout(settleTimer);
    };
  }, [handleScroll, syncActivePostFromScroll]);

  const displayPosts = useMemo(
    () =>
      visiblePosts.length > 0
        ? visiblePosts
        : instantPost
          ? [instantPost]
          : [],
    [visiblePosts, instantPost]
  );

  const activeIndex = useMemo(
    () => displayPosts.findIndex((p) => String(p._id) === String(activePostId)),
    [displayPosts, activePostId]
  );

  useEffect(() => {
    if (activeIndex < 0 || !displayPosts.length) return;

    const nearby = displayPosts.slice(
      Math.max(0, activeIndex - 1),
      Math.min(displayPosts.length, activeIndex + 3)
    );
    prefetchPostVideos(nearby, "high");
  }, [activeIndex, displayPosts]);

  useEffect(() => {
    if (activeIndex < 0) return;
    if (
      activeIndex >= visiblePosts.length - PREFETCH_AHEAD &&
      hasNextPage &&
      !isFetchingNextPage
    ) {
      fetchNextPage();
    }
  }, [
    activeIndex,
    visiblePosts.length,
    hasNextPage,
    isFetchingNextPage,
    fetchNextPage,
  ]);

  useEffect(() => {
    if (!feedFetchEnabled || !canFetchFeed) return;
    if (!hasNextPage || isFetchingNextPage) return;
    if ((data?.pages?.length ?? 0) >= 2) return;

    const timer = window.setTimeout(() => {
      fetchNextPage();
    }, REELS_BG_PREFETCH_DELAY_MS);

    return () => window.clearTimeout(timer);
  }, [
    feedFetchEnabled,
    canFetchFeed,
    data?.pages?.length,
    hasNextPage,
    isFetchingNextPage,
    fetchNextPage,
  ]);

  const handleTabChange = useCallback(
    (tab: ReelsTab) => {
      setReelsTab(tab);
      const params = new URLSearchParams();
      Object.entries(searchParamsProp).forEach(([key, value]) => {
        if (value) params.set(key, value);
      });
      params.set("feed", feedMode === "explore" ? "explore" : "home");
      params.set("tab", tab);
      router.replace(`${pathname}?${params.toString()}`, { scroll: false });
    },
    [pathname, router, searchParamsProp, feedMode]
  );

  const handleFollowedFromSuggestions = useCallback(() => {
    queryClient.invalidateQueries({ queryKey: ["post-feed"] });
  }, [queryClient]);

  const showFollowingSuggestions =
    reelsTab === "following" &&
    !requiresAuth &&
    suggestedUsers.length > 0 &&
    !followingSuggestionsDismissed;

  const showAuthRequired = requiresAuth;
  const showEmptySavedMessage = emptySaved && !requiresAuth;
  const showEmptyFollowingMessage =
    emptyFollowing &&
    !isLoading &&
    (followingSuggestionsDismissed || suggestedUsers.length === 0);
  const showNearMeLocationError =
    reelsTab === "near_me" && (nearMeLocationError || needsLocation);
  const showEmptyNearMeMessage =
    emptyNearMe && !showNearMeLocationError && !isLoading;
  const showNoPosts =
    !instantPost &&
    !showAuthRequired &&
    !showFollowingSuggestions &&
    !showEmptySavedMessage &&
    !showEmptyFollowingMessage &&
    !showNearMeLocationError &&
    !showEmptyNearMeMessage &&
    (isError || (displayPosts.length === 0 && !isLoading && canFetchFeed));

  if (!instantPost && !canFetchFeed && isLoading) {
    return <PageLoader className="min-h-[100dvh]" />;
  }

  if (
    showReelsTabs &&
    reelsTab === "near_me" &&
    !nearMeCoords &&
    !nearMeLocationError
  ) {
    return <PageLoader className="min-h-[100dvh]" />;
  }

  if (showNoPosts) {
    return (
      <div className="relative min-h-[100dvh] bg-black">
        <p className="py-20 text-center text-neutral-400">{t("posts.notFound")}</p>
      </div>
    );
  }

  return (
    <ExploreReelsUiProvider>
    <MutedProvider>
      <div className="relative min-h-[100dvh] overflow-x-hidden bg-black">
        {showReelsTabs ? (
          <div className="pointer-events-none fixed inset-x-0 top-0 z-[90] pt-[calc(2.25rem+env(safe-area-inset-top))]">
            <div className="pointer-events-auto mx-auto w-full max-w-xl px-4 pb-2">
              <ReelsTabBar activeTab={reelsTab} onChange={handleTabChange} />
            </div>
          </div>
        ) : null}

        {showFollowingSuggestions ? (
          <FollowingSuggestionsCarousel
            users={suggestedUsers}
            onFollowed={handleFollowedFromSuggestions}
            onDismiss={() => setFollowingSuggestionsDismissed(true)}
          />
        ) : showAuthRequired ? (
          <div className="flex min-h-[70dvh] flex-col items-center justify-center px-6 text-center text-white/70">
            <p className="text-base font-semibold text-white">{t("posts.loginRequired")}</p>
            <p className="mt-2 text-sm">
              {reelsTab === "saved"
                ? t("posts.loginRequiredSaved")
                : t("posts.loginRequiredFollowing")}
            </p>
          </div>
        ) : showEmptySavedMessage ? (
          <div className="flex min-h-[70dvh] flex-col items-center justify-center px-6 text-center text-white/70">
            <p className="text-base font-semibold text-white">{t("posts.noSavedPosts")}</p>
            <p className="mt-2 text-sm">{t("posts.noSavedPostsHint")}</p>
          </div>
        ) : showEmptyFollowingMessage ? (
          <div className="flex min-h-[70dvh] flex-col items-center justify-center px-6 text-center text-white/70">
            <p className="text-base font-semibold text-white">{t("posts.notFollowingAnyone")}</p>
            <p className="mt-2 text-sm">{t("posts.notFollowingAnyoneHint")}</p>
          </div>
        ) : showNearMeLocationError ? (
          <div className="flex min-h-[70dvh] flex-col items-center justify-center px-6 text-center text-white/70">
            <p className="text-base font-semibold text-white">{t("posts.locationAccessTitle")}</p>
            <p className="mt-2 text-sm">{t("posts.locationAccessHint")}</p>
          </div>
        ) : showEmptyNearMeMessage ? (
          <div className="flex min-h-[70dvh] flex-col items-center justify-center px-6 text-center text-white/70">
            <p className="text-base font-semibold text-white">{t("posts.noNearbyReels")}</p>
            <p className="mt-2 text-sm">{t("posts.noNearbyReelsHint")}</p>
          </div>
        ) : displayPosts.length > 0 ? (
          <div className={REELS_SHELL_CLASS}>
          <div ref={scrollRef} className={REELS_SCROLL_CLASS}>
            {displayPosts.map((post, index) => {
              const preloadPriority: VideoPreloadPriority =
                index === activeIndex
                  ? "active"
                  : Math.abs(index - activeIndex) === 1
                    ? "nearby"
                    : "idle";

              return (
              <ReelsScrollSlot
                key={post._id}
                index={index}
                activeIndex={activeIndex >= 0 ? activeIndex : 0}
              >
                <ReelsPostCard
                  postData={post}
                  isActive={String(post._id) === String(activePostId)}
                  postPage={feedMode === "user" && showClose}
                  preloadPriority={preloadPriority}
                />
              </ReelsScrollSlot>
              );
            })}
          </div>
          </div>
        ) : null}
      </div>
    </MutedProvider>
    </ExploreReelsUiProvider>
  );
}
