"use client";

import React, {
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { useSearchParams } from "next/navigation";
import { useInfiniteQuery } from "@tanstack/react-query";
import Cookies from "js-cookie";
import { fetchPosts } from "@/api/fetchPosts";
import { fetchPostById } from "@/api/fetchPostById";
import {
  AcademyExploreItem,
  fetchAcademyExplore,
} from "@/api/fetchAcademyExplore";
import { trackExploreInteraction } from "@/api/trackExploreInteraction";
import { Post } from "@/types/types";
import { MutedProvider } from "@/components/models/ModelPage/MainModelCardPost";
import ReelsPostCard from "@/components/posts/ReelsPostCard";
import ReelsAcademyCard from "@/components/explore/ReelsAcademyCard";
import PageLoader from "@/components/ui/PageLoader";
import { ExploreFilterId } from "@/constants/exploreFilters";
import { buildExplorePostFilters } from "@/lib/explore/buildPostFilters";
import {
  isPublicAcademyStatus,
  isPublicPostStatus,
} from "@/lib/moderationStatus";
import {
  postMatchesReelsMediaType,
  resolveReelsMediaType,
  type ReelsMediaType,
} from "@/lib/reelsMediaType";
import { useReelsSnapScroll, REELS_SCROLL_CLASS, getReelsStepHeight } from "@/hooks/useReelsSnapScroll";
import ReelsScrollSlot from "@/components/posts/ReelsScrollSlot";
import { ExploreReelsUiProvider } from "@/contexts/ExploreReelsUiContext";
import {
  REELS_BG_PREFETCH_DELAY_MS,
  REELS_FIRST_PAGE_SIZE,
  REELS_PAGE_SIZE,
  REELS_PREFETCH_AHEAD,
  REELS_SLOT_CLASS,
  REELS_SHELL_CLASS,
} from "@/constants/reelsFeed";
import { useTranslation } from "react-i18next";

// چند آیتم مانده به انتها، صفحهٔ بعد در پس‌زمینه پیش‌بارگذاری شود
const PREFETCH_AHEAD = REELS_PREFETCH_AHEAD;

export type ExploreReelItem =
  | { kind: "post"; key: string; post: Post }
  | { kind: "academy"; key: string; academy: AcademyExploreItem };

type ExploreReelsViewProps = {
  initialId: string;
  initialType?: "post" | "academy";
  showClose?: boolean;
};

function interleaveAcademy(
  posts: ExploreReelItem[],
  academy: ExploreReelItem[],
  page: number
): ExploreReelItem[] {
  if (!academy.length) return posts;
  const result: ExploreReelItem[] = [];
  let academyIdx = 0;
  const interval = 5;

  posts.forEach((post, index) => {
    result.push(post);
    const globalIndex = (page - 1) * posts.length + index;
    if ((globalIndex + 1) % interval === 0 && academyIdx < academy.length) {
      result.push(academy[academyIdx]);
      academyIdx += 1;
    }
  });

  while (academyIdx < academy.length) {
    result.push(academy[academyIdx]);
    academyIdx += 1;
  }

  return result;
}

export default function ExploreReelsView({
  initialId,
  initialType = "post",
}: ExploreReelsViewProps) {
  const { t } = useTranslation("common");
  const searchParams = useSearchParams();
  const token = Cookies.get("token") || "";
  const scrollRef = useRef<HTMLDivElement>(null);
  useReelsSnapScroll(scrollRef);
  const scrolledRef = useRef(false);

  const filterParam = (searchParams.get("filter") ||
    "all") as ExploreFilterId;
  const lat = searchParams.get("lat");
  const lng = searchParams.get("lng");
  const coords =
    lat && lng ? { lat: parseFloat(lat), lng: parseFloat(lng) } : null;

  const postFilters = buildExplorePostFilters(filterParam, coords);
  const includeAcademy =
    filterParam === "all" || filterParam === "academy";
  const academyOnly = filterParam === "academy";

  const initialKey =
    initialType === "academy" ? `academy-${initialId}` : `post-${initialId}`;
  const [activeKey, setActiveKey] = useState(initialKey);
  const [seedMediaType, setSeedMediaType] = useState<ReelsMediaType | undefined>();

  useEffect(() => {
    if (initialType !== "post") return;
    let cancelled = false;
    fetchPostById(initialId, token).then((post) => {
      if (cancelled) return;
      setSeedMediaType(resolveReelsMediaType(post));
    });
    return () => {
      cancelled = true;
    };
  }, [initialId, initialType, token]);

  const { data, isLoading, isError, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useInfiniteQuery({
      queryKey: [
        "explore-reels",
        filterParam,
        coords?.lat,
        coords?.lng,
        postFilters,
        academyOnly,
        initialId,
        initialType,
        seedMediaType,
      ],
      enabled:
        !(filterParam === "near_me" && !coords) &&
        (initialType !== "post" || seedMediaType !== undefined),
      queryFn: async ({ pageParam = 1 }) => {
        const page = pageParam as number;

        if (academyOnly) {
          const academyResult = await fetchAcademyExplore(page, 10, token);
          return {
            page,
            posts: [] as Post[],
            academyItems: academyResult.items,
            hasMore: academyResult.hasNextPage,
          };
        }

        const pageSize = page === 1 ? REELS_FIRST_PAGE_SIZE : REELS_PAGE_SIZE;

        const [postsResult, academyResult] = await Promise.all([
          fetchPosts(
            page,
            pageSize,
            {
              ...postFilters,
              feedMode: "reels",
              ...(seedMediaType ? { type: seedMediaType } : {}),
              ...(page === 1 ? { seedPostId: initialId } : {}),
            },
            token
          ),
          includeAcademy
            ? fetchAcademyExplore(page, 10, token)
            : Promise.resolve({ items: [], hasNextPage: false }),
        ]);

        return {
          page,
          posts: postsResult.posts ?? [],
          academyItems: academyResult.items,
          hasMore:
            (postsResult.posts?.length ?? 0) > 0 ||
            academyResult.hasNextPage,
        };
      },
      getNextPageParam: (lastPage, pages) =>
        lastPage.hasMore ? pages.length + 1 : undefined,
      initialPageParam: 1,
    });

  const items: ExploreReelItem[] = useMemo(() => {
    const seen = new Set<string>();
    const merged: ExploreReelItem[] = [];

    for (const page of data?.pages ?? []) {
      const pagePosts: ExploreReelItem[] = [];
      const pageAcademy: ExploreReelItem[] = [];

      for (const post of page.posts) {
        if (!isPublicPostStatus(post.status)) continue;
        if (
          initialType === "post" &&
          seedMediaType &&
          !postMatchesReelsMediaType(post, seedMediaType)
        ) {
          continue;
        }
        const key = `post-${post._id}`;
        if (seen.has(key)) continue;
        seen.add(key);
        pagePosts.push({ kind: "post", key, post });
      }

      if (includeAcademy) {
        for (const academy of page.academyItems) {
          if (academy.status && !isPublicAcademyStatus(academy.status)) continue;
          const key = `academy-${academy._id}`;
          if (seen.has(key)) continue;
          seen.add(key);
          pageAcademy.push({ kind: "academy", key, academy });
        }
      }

      const pageItems =
        filterParam === "all" || filterParam === "academy"
          ? interleaveAcademy(pagePosts, pageAcademy, page.page)
          : [...pagePosts, ...pageAcademy];

      merged.push(...pageItems);
    }

    if (filterParam === "trending" || filterParam === "best_month") {
      return merged.sort((a, b) => {
        const scoreA =
          a.kind === "post"
            ? (a.post.likesCount ?? 0) + (a.post.commentsCount ?? 0)
            : a.academy.likesCount ?? 0;
        const scoreB =
          b.kind === "post"
            ? (b.post.likesCount ?? 0) + (b.post.commentsCount ?? 0)
            : b.academy.likesCount ?? 0;
        return scoreB - scoreA;
      });
    }

    return merged;
  }, [data, filterParam, includeAcademy, initialType, seedMediaType]);

  useLayoutEffect(() => {
    if (scrolledRef.current || !items.length || !scrollRef.current) return;
    const idx = items.findIndex((item) => item.key === initialKey);
    const targetIdx = idx >= 0 ? idx : 0;
    scrollRef.current.scrollTo({
      top: targetIdx * getReelsStepHeight(scrollRef.current),
      behavior: "auto",
    });
    scrolledRef.current = true;
    setActiveKey(items[targetIdx]?.key || initialKey);
  }, [items, initialKey]);

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

    const step = getReelsStepHeight(el);
    const index = Math.min(
      items.length - 1,
      Math.max(0, Math.round(el.scrollTop / step))
    );
    const item = items[index];
    if (item && item.key !== activeKey) {
      setActiveKey(item.key);
    }
  }, [items, activeKey]);

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

    const step = getReelsStepHeight(el);
    const index = Math.round(el.scrollTop / step);

    if (
      index >= items.length - PREFETCH_AHEAD &&
      hasNextPage &&
      !isFetchingNextPage
    ) {
      fetchNextPage();
    }
  }, [items.length, hasNextPage, isFetchingNextPage, fetchNextPage]);

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

    let settleTimer: number | null = null;

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

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

    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, syncActiveFromScroll]);

  // بافر پس‌زمینه: با نزدیک‌شدن به انتهای آیتم‌های لودشده، صفحهٔ بعد از قبل گرفته می‌شود
  const activeIndex = useMemo(
    () => items.findIndex((i) => i.key === activeKey),
    [items, activeKey]
  );

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

  useEffect(() => {
    if (!data?.pages?.[0]) 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);
  }, [data?.pages?.length, hasNextPage, isFetchingNextPage, fetchNextPage]);

  useEffect(() => {
    if (!token) return;
    const item = items.find((i) => i.key === activeKey);
    if (!item || item.kind !== "academy") return;

    trackExploreInteraction(
      {
        targetType: "academy",
        targetId: item.academy._id,
        authorId: item.academy.user_id,
        contentType: "academy",
        action: "view",
      },
      token
    );
  }, [activeKey, items, token]);

  if (filterParam === "near_me" && !coords) {
    return (
      <p className="py-20 text-center text-neutral-500">
        {t("reels.locationNotFound")}
      </p>
    );
  }

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

  if (isError || !items.length) {
    return (
      <p className="py-20 text-center text-neutral-500">{t("reels.contentNotFound")}</p>
    );
  }

  return (
    <ExploreReelsUiProvider>
      <MutedProvider>
        <div className="relative min-h-[100dvh] bg-black">
        <div className={REELS_SHELL_CLASS}>
        <div
          ref={scrollRef}
          className={REELS_SCROLL_CLASS}
        >
          {items.map((item, index) => (
            <ReelsScrollSlot
              key={item.key}
              index={index}
              activeIndex={activeIndex >= 0 ? activeIndex : 0}
            >
              {item.kind === "post" ? (
                <ReelsPostCard
                  postData={item.post}
                  isActive={item.key === activeKey}
                />
              ) : (
                <ReelsAcademyCard
                  item={item.academy}
                  isActive={item.key === activeKey}
                />
              )}
            </ReelsScrollSlot>
          ))}
          {isFetchingNextPage ? (
            <div className={REELS_SLOT_CLASS} aria-hidden />
          ) : null}
        </div>
        </div>
      </div>
    </MutedProvider>
    </ExploreReelsUiProvider>
  );
}
