import { Ionicons } from "@expo/vector-icons";
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import {
  type QueryFunction,
  type QueryKey,
  useInfiniteQuery,
} from "@tanstack/react-query";
import { useSegments } from "expo-router";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import {
  ActivityIndicator,
  FlatList,
  View,
  type ViewProps,
} from "react-native";
import { Text } from "@/components/common/Text";
import { getItemNavigation } from "@/components/common/TouchableItemRouter";
import MoviePoster from "@/components/posters/MoviePoster.tv";
import { TVFocusablePoster } from "@/components/tv/TVFocusablePoster";
import { useScaledTVPosterSizes } from "@/constants/TVPosterSizes";
import { useScaledTVTypography } from "@/constants/TVTypography";
import useRouter from "@/hooks/useAppRouter";
import { SortByOption, SortOrderOption } from "@/utils/atoms/filters";
import ContinueWatchingPoster from "../ContinueWatchingPoster.tv";
import SeriesPoster from "../posters/SeriesPoster.tv";

const ITEM_GAP = 24;
// Extra padding to accommodate scale animation (1.05x) and glow shadow
const SCALE_PADDING = 20;

interface Props extends ViewProps {
  title?: string | null;
  orientation?: "horizontal" | "vertical";
  disabled?: boolean;
  queryKey: QueryKey;
  queryFn: QueryFunction<BaseItemDto[], QueryKey, number>;
  hideIfEmpty?: boolean;
  pageSize?: number;
  onPressSeeAll?: () => void;
  enabled?: boolean;
  onLoaded?: () => void;
  isFirstSection?: boolean;
  onItemFocus?: (item: BaseItemDto) => void;
  parentId?: string;
}

type Typography = ReturnType<typeof useScaledTVTypography>;

// TV-specific ItemCardText with larger fonts
const TVItemCardText: React.FC<{
  item: BaseItemDto;
  typography: Typography;
}> = ({ item, typography }) => {
  return (
    <View style={{ marginTop: 12, flexDirection: "column" }}>
      {item.Type === "Episode" ? (
        <>
          <Text
            numberOfLines={1}
            style={{ fontSize: typography.callout, color: "#FFFFFF" }}
          >
            {item.Name}
          </Text>
          <Text
            numberOfLines={1}
            style={{
              fontSize: typography.callout,
              color: "#9CA3AF",
              marginTop: 2,
            }}
          >
            {`S${item.ParentIndexNumber?.toString()}:E${item.IndexNumber?.toString()}`}
            {" - "}
            {item.SeriesName}
          </Text>
        </>
      ) : (
        <>
          <Text
            numberOfLines={1}
            style={{ fontSize: typography.callout, color: "#FFFFFF" }}
          >
            {item.Name}
          </Text>
          <Text
            style={{
              fontSize: typography.callout,
              color: "#9CA3AF",
              marginTop: 2,
            }}
          >
            {item.ProductionYear}
          </Text>
        </>
      )}
    </View>
  );
};

type PosterSizes = ReturnType<typeof useScaledTVPosterSizes>;

// TV-specific "See All" card for end of lists
const TVSeeAllCard: React.FC<{
  onPress: () => void;
  orientation: "horizontal" | "vertical";
  disabled?: boolean;
  onFocus?: () => void;
  onBlur?: () => void;
  typography: Typography;
  posterSizes: PosterSizes;
}> = ({
  onPress,
  orientation,
  disabled,
  onFocus,
  onBlur,
  typography,
  posterSizes,
}) => {
  const { t } = useTranslation();
  const width =
    orientation === "horizontal" ? posterSizes.landscape : posterSizes.poster;
  const aspectRatio = orientation === "horizontal" ? 16 / 9 : 10 / 15;

  return (
    <View style={{ width }}>
      <TVFocusablePoster
        onPress={onPress}
        disabled={disabled}
        onFocus={onFocus}
        onBlur={onBlur}
      >
        <View
          style={{
            width,
            aspectRatio,
            borderRadius: 24,
            backgroundColor: "rgba(255, 255, 255, 0.08)",
            justifyContent: "center",
            alignItems: "center",
            borderWidth: 1,
            borderColor: "rgba(255, 255, 255, 0.15)",
          }}
        >
          <Ionicons
            name='arrow-forward'
            size={32}
            color='white'
            style={{ marginBottom: 8 }}
          />
          <Text
            style={{
              fontSize: typography.callout,
              color: "#FFFFFF",
              fontWeight: "600",
            }}
          >
            {t("common.seeAll", { defaultValue: "See all" })}
          </Text>
        </View>
      </TVFocusablePoster>
    </View>
  );
};

export const InfiniteScrollingCollectionList: React.FC<Props> = ({
  title,
  orientation = "vertical",
  disabled = false,
  queryFn,
  queryKey,
  hideIfEmpty = false,
  pageSize = 10,
  enabled = true,
  onLoaded,
  isFirstSection = false,
  onItemFocus,
  parentId,
  ...props
}) => {
  const typography = useScaledTVTypography();
  const posterSizes = useScaledTVPosterSizes();
  const effectivePageSize = Math.max(1, pageSize);
  const hasCalledOnLoaded = useRef(false);
  const router = useRouter();
  const segments = useSegments();
  const from = (segments as string[])[2] || "(home)";

  // Track focus within section for item focus/blur callbacks
  const flatListRef = useRef<FlatList<BaseItemDto>>(null);
  const [_focusedCount, setFocusedCount] = useState(0);

  const handleItemFocus = useCallback(
    (item: BaseItemDto) => {
      setFocusedCount((c) => c + 1);
      onItemFocus?.(item);
    },
    [onItemFocus],
  );

  const handleItemBlur = useCallback(() => {
    setFocusedCount((c) => Math.max(0, c - 1));
  }, []);

  // Focus handler for See All card (doesn't need item parameter)
  const handleSeeAllFocus = useCallback(() => {
    setFocusedCount((c) => c + 1);
  }, []);

  const {
    data,
    isLoading,
    isFetchingNextPage,
    hasNextPage,
    fetchNextPage,
    isSuccess,
  } = useInfiniteQuery({
    queryKey: queryKey,
    queryFn: ({ pageParam = 0, ...context }) =>
      queryFn({ ...context, queryKey, pageParam }),
    getNextPageParam: (lastPage, allPages) => {
      if (lastPage.length < effectivePageSize) {
        return undefined;
      }
      return allPages.reduce((acc, page) => acc + page.length, 0);
    },
    initialPageParam: 0,
    staleTime: 60 * 1000,
    refetchInterval: 60 * 1000,
    refetchOnWindowFocus: false,
    refetchOnReconnect: true,
    enabled,
  });

  useEffect(() => {
    if (isSuccess && !hasCalledOnLoaded.current && onLoaded) {
      hasCalledOnLoaded.current = true;
      onLoaded();
    }
  }, [isSuccess, onLoaded]);

  const { t } = useTranslation();

  const allItems = useMemo(() => {
    const items = data?.pages.flat() ?? [];
    const seen = new Set<string>();
    const deduped: BaseItemDto[] = [];

    for (const item of items) {
      const id = item.Id;
      if (!id) continue;
      if (seen.has(id)) continue;
      seen.add(id);
      deduped.push(item);
    }

    return deduped;
  }, [data]);

  const itemWidth =
    orientation === "horizontal" ? posterSizes.landscape : posterSizes.poster;

  const handleItemPress = useCallback(
    (item: BaseItemDto) => {
      const navigation = getItemNavigation(item, from);
      router.push(navigation as any);
    },
    [from, router],
  );

  const handleEndReached = useCallback(() => {
    if (hasNextPage && !isFetchingNextPage) {
      fetchNextPage();
    }
  }, [hasNextPage, isFetchingNextPage, fetchNextPage]);

  const handleSeeAllPress = useCallback(() => {
    if (!parentId) return;
    router.push({
      pathname: "/(auth)/(tabs)/(libraries)/[libraryId]",
      params: {
        libraryId: parentId,
        sortBy: SortByOption.DateCreated,
        sortOrder: SortOrderOption.Descending,
      },
    } as any);
  }, [router, parentId]);

  const getItemLayout = useCallback(
    (_data: ArrayLike<BaseItemDto> | null | undefined, index: number) => ({
      length: itemWidth + ITEM_GAP,
      offset: (itemWidth + ITEM_GAP) * index,
      index,
    }),
    [itemWidth],
  );

  const renderItem = useCallback(
    ({ item, index }: { item: BaseItemDto; index: number }) => {
      const isFirstItem = isFirstSection && index === 0;
      const isHorizontal = orientation === "horizontal";

      const renderPoster = () => {
        if (item.Type === "Episode" && isHorizontal) {
          return <ContinueWatchingPoster item={item} />;
        }
        if (item.Type === "Episode" && !isHorizontal) {
          return <SeriesPoster item={item} />;
        }
        if (item.Type === "Movie" && isHorizontal) {
          return <ContinueWatchingPoster item={item} />;
        }
        if (item.Type === "Movie" && !isHorizontal) {
          return <MoviePoster item={item} />;
        }
        if (item.Type === "Series" && !isHorizontal) {
          return <SeriesPoster item={item} />;
        }
        if (item.Type === "Series" && isHorizontal) {
          return <ContinueWatchingPoster item={item} />;
        }
        if (item.Type === "Program") {
          return <ContinueWatchingPoster item={item} />;
        }
        if (item.Type === "BoxSet" && !isHorizontal) {
          return <MoviePoster item={item} />;
        }
        if (item.Type === "BoxSet" && isHorizontal) {
          return <ContinueWatchingPoster item={item} />;
        }
        if (item.Type === "Playlist" && !isHorizontal) {
          return <MoviePoster item={item} />;
        }
        if (item.Type === "Playlist" && isHorizontal) {
          return <ContinueWatchingPoster item={item} />;
        }
        if (item.Type === "Video" && !isHorizontal) {
          return <MoviePoster item={item} />;
        }
        if (item.Type === "Video" && isHorizontal) {
          return <ContinueWatchingPoster item={item} />;
        }
        // Default fallback
        return isHorizontal ? (
          <ContinueWatchingPoster item={item} />
        ) : (
          <MoviePoster item={item} />
        );
      };

      return (
        <View style={{ marginRight: ITEM_GAP, width: itemWidth }}>
          <TVFocusablePoster
            onPress={() => handleItemPress(item)}
            hasTVPreferredFocus={isFirstItem}
            onFocus={() => handleItemFocus(item)}
            onBlur={handleItemBlur}
          >
            {renderPoster()}
          </TVFocusablePoster>
          <TVItemCardText item={item} typography={typography} />
        </View>
      );
    },
    [
      orientation,
      isFirstSection,
      itemWidth,
      handleItemPress,
      handleItemFocus,
      handleItemBlur,
      typography,
    ],
  );

  if (hideIfEmpty === true && allItems.length === 0 && !isLoading) return null;
  if (disabled || !title) return null;

  return (
    <View style={{ overflow: "visible" }} {...props}>
      {/* Section Header */}
      <Text
        style={{
          fontSize: typography.heading,
          fontWeight: "700",
          color: "#FFFFFF",
          marginBottom: 20,
          marginLeft: SCALE_PADDING,
          letterSpacing: 0.5,
        }}
      >
        {title}
      </Text>

      {isLoading === false && allItems.length === 0 && (
        <Text
          style={{
            color: "#737373",
            fontSize: typography.callout,
            marginLeft: SCALE_PADDING,
          }}
        >
          {t("home.no_items")}
        </Text>
      )}

      {isLoading ? (
        <View
          style={{
            flexDirection: "row",
            gap: ITEM_GAP,
            paddingHorizontal: SCALE_PADDING,
            paddingVertical: SCALE_PADDING,
          }}
        >
          {[1, 2, 3, 4, 5].map((i) => (
            <View key={i} style={{ width: itemWidth }}>
              <View
                style={{
                  backgroundColor: "#262626",
                  width: itemWidth,
                  aspectRatio: orientation === "horizontal" ? 16 / 9 : 10 / 15,
                  borderRadius: 12,
                  marginBottom: 8,
                }}
              />
              <View
                style={{
                  borderRadius: 6,
                  overflow: "hidden",
                  marginBottom: 4,
                  alignSelf: "flex-start",
                }}
              >
                <Text
                  style={{
                    color: "#262626",
                    backgroundColor: "#262626",
                    borderRadius: 6,
                    fontSize: typography.callout,
                  }}
                  numberOfLines={1}
                >
                  Placeholder text here
                </Text>
              </View>
            </View>
          ))}
        </View>
      ) : (
        <FlatList
          ref={flatListRef}
          horizontal
          data={allItems}
          keyExtractor={(item) => item.Id!}
          renderItem={renderItem}
          showsHorizontalScrollIndicator={false}
          onEndReached={handleEndReached}
          onEndReachedThreshold={0.5}
          initialNumToRender={5}
          maxToRenderPerBatch={3}
          windowSize={5}
          removeClippedSubviews={false}
          getItemLayout={getItemLayout}
          maintainVisibleContentPosition={{ minIndexForVisible: 0 }}
          style={{ overflow: "visible" }}
          contentContainerStyle={{
            paddingVertical: SCALE_PADDING,
            paddingHorizontal: SCALE_PADDING,
          }}
          ListFooterComponent={
            <View
              style={{
                flexDirection: "row",
                alignItems: "center",
              }}
            >
              {isFetchingNextPage && (
                <View
                  style={{
                    marginLeft: itemWidth / 2,
                    marginRight: ITEM_GAP,
                    justifyContent: "center",
                    height: orientation === "horizontal" ? 191 : 315,
                  }}
                >
                  <ActivityIndicator size='small' color='white' />
                </View>
              )}
              {parentId && allItems.length > 0 && (
                <TVSeeAllCard
                  onPress={handleSeeAllPress}
                  orientation={orientation}
                  disabled={disabled}
                  onFocus={handleSeeAllFocus}
                  onBlur={handleItemBlur}
                  typography={typography}
                  posterSizes={posterSizes}
                />
              )}
            </View>
          }
        />
      )}
    </View>
  );
};
