import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Search, Star, Play, ChevronDown, RefreshCw, Loader2, X } from "lucide-react";
import { useTranslation } from "react-i18next";
import PageLayout from "@/components/PageLayout";
import NoServerPrompt from "@/components/NoServerPrompt";
import VideoPlayer from "@/components/VideoPlayer";
import InlineAdSlot from "@/components/InlineAdSlot";
import LazyImage from "@/components/LazyImage";
import { useProfiles } from "@/hooks/useProfiles";
import { useMovies, useReloadPlaylist } from "@/hooks/useXtreamData";
import { useFavorites } from "@/hooks/useFavorites";
import type { Movie } from "@/types/xtream";
import { FocusableSection, FocusableTile, FocusableButton } from "@/components/focusable";
import { useTriggerInterstitial } from "@/hooks/useAdMob";
import { useEntitlement } from "@/hooks/useEntitlement";
import { useAdFreeUnlock } from "@/hooks/useAdFreeUnlock";
import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
import { isProxiedProfile } from "@/lib/proxyUrl";

// Insert an inline ad slot every N items in the grid. Lower number =
// ad appears sooner so QA can verify rendering on the first scroll
// without having to scroll past 12+ posters.
const AD_SLOT_EVERY = 6;

// ── Pagination: render in pages of 50, load more on scroll ──
const PAGE_SIZE = 50;

const Movies = () => {
  const { vodProfile, activeProfile } = useProfiles();
  const effectiveProfile = vodProfile || activeProfile;
  const { t } = useTranslation();
  const { data: movies = [], isLoading, error } = useMovies(effectiveProfile);
  const reload = useReloadPlaylist();
  const { isFavorite, toggle } = useFavorites(effectiveProfile?.id, "movie");

  const [search, setSearch] = useState("");
  const [selectedCategory, setSelectedCategory] = useState("All");
  const [playing, setPlaying] = useState<Movie | null>(null);
  const [visibleCount, setVisibleCount] = useState(PAGE_SIZE);

  // FEATURE (2026-01): banner is now mounted GLOBALLY in App.tsx via
  // useGlobalBanner() so it persists across Home / Movies / Series /
  // Account / Live TV without the show→hide flicker that per-page
  // mounts caused. Nothing to wire up locally.
  const fireInterstitial = useTriggerInterstitial();
  const { adsEnabled } = useEntitlement();
  // Inline sponsored slots fire the SAME rewarded unlock as Live TV
  // (3 ads = 1 ad-free hour) instead of a plain interstitial, so they
  // count toward the user's ad-free progress.
  const { watchAd: watchRewardAd } = useAdFreeUnlock({ adsToWatch: 3, hoursPerUnlock: 1 });

  const openMovie = (m: Movie) => {
    // UX fix (2026-06): open the player IMMEDIATELY to avoid tap-delay
    // perception on slower phones. We keep monetisation on exit only.
    setPlaying(m);
  };

  const closeMovie = async () => {
    setPlaying(null);
    // Fire an interstitial AFTER exiting playback.
    await fireInterstitial();
  };

  const categories = ["All", ...Array.from(new Set(movies.map((m) => m.category)))];

  const filtered = movies.filter((m) => {
    const matchSearch = m.name.toLowerCase().includes(search.toLowerCase());
    const matchCat = selectedCategory === "All" || m.category === selectedCategory;
    return matchSearch && matchCat;
  });

  // Reset pagination when search/category changes
  const filteredKey = `${search}|${selectedCategory}`;
  const [prevFilterKey, setPrevFilterKey] = useState(filteredKey);
  if (filteredKey !== prevFilterKey) {
    setPrevFilterKey(filteredKey);
    setVisibleCount(PAGE_SIZE);
  }

  // Only render what's visible (pagination)
  const visibleMovies = filtered.slice(0, visibleCount);
  const hasMore = visibleCount < filtered.length;

  // FEATURE (2026-01) — infinite scroll. Sentinel rendered at the end
  // of the grid; when it enters the viewport (200 px lookahead) we
  // automatically bump `visibleCount` by another PAGE_SIZE. Removes
  // the manual "Load More" button and the redundant total counter
  // that used to sit at the bottom and ate vertical real-estate.
  const { sentinelRef } = useInfiniteScroll({
    hasMore,
    onLoadMore: () => setVisibleCount((c) => c + PAGE_SIZE),
  });

  if (!effectiveProfile) {
    return (
      <PageLayout title={t("movies.title")}>
        <NoServerPrompt testIdPrefix="movies" />
      </PageLayout>
    );
  }

  return (
    <PageLayout title={t("movies.title")}>
      <div className="flex flex-col gap-2 h-full min-h-0">
        <div className="flex gap-2 shrink-0">
          <div className="glass-card rounded-xl px-3 py-2 flex items-center gap-2 w-40">
            <ChevronDown className="w-4 h-4 text-muted-foreground" />
            <select value={selectedCategory} onChange={(e) => setSelectedCategory(e.target.value)} className="bg-transparent text-foreground text-xs outline-none flex-1">
              {categories.map((c) => <option key={c} value={c} className="bg-background">{c === "All" ? t("common.all") : c}</option>)}
            </select>
          </div>
          <div className="glass-card rounded-xl px-3 py-2 flex items-center gap-2 flex-1">
            <Search className="w-4 h-4 text-muted-foreground" />
            <input type="text" placeholder={t("movies.searchPlaceholder")} value={search} onChange={(e) => setSearch(e.target.value)}
              className="bg-transparent text-foreground placeholder:text-muted-foreground text-xs outline-none flex-1" />
          </div>
          <button onClick={() => reload(activeProfile.id)} className="glass-card rounded-xl px-3 py-2">
            <RefreshCw className="w-4 h-4 text-muted-foreground" />
          </button>
        </div>

        {isLoading && (
          <div className="flex items-center justify-center py-6">
            <Loader2 className="w-6 h-6 text-primary animate-spin" />
          </div>
        )}
        {error && <p className="text-destructive text-xs">{t("movies.failedLoad")}</p>}

        <FocusableSection
          autoFocus
          focusKey="movies-grid"
          className="flex-1 min-h-0 overflow-y-auto gap-2 grid"
          style={{
            // Adaptive grid: 110px min keeps phones at 3 cols, tablets
            // at 5–7, large landscape phones at 10+. Cards stay 2:3 so
            // the height shrinks proportionally — never stretched.
            gridTemplateColumns: "repeat(auto-fill, minmax(110px, 1fr))",
            gridAutoRows: "max-content",
            // Edge-to-edge: the grid flows all the way to the bottom
            // ad banner — PageLayout already reserves the banner
            // height via --ad-banner-bottom-h / --tv-banner-h. We add
            // the tiny safe-area inset only.
            paddingBottom: "env(safe-area-inset-bottom, 0px)",
            // Pro-app feel: contain overscroll bounce + restrict to
            // vertical pan so pinch-zoom can't break the layout.
            overscrollBehavior: "contain",
            touchAction: "pan-y",
          }}
        >
          {visibleMovies.flatMap((movie, idx) => {
            const tile = (
              <FocusableTile
                key={movie.id}
                focusKey={`movie-${movie.id}`}
                onEnter={() => void openMovie(movie)}
                onClick={() => void openMovie(movie)}
                className="glass-card rounded-xl overflow-hidden cursor-pointer group hover:border-primary/30 transition-all border-transparent flex flex-col"
              >
                <div
                  className="w-full bg-muted/20 flex items-center justify-center relative overflow-hidden"
                  style={{ aspectRatio: "2 / 3" }}
                >
                  {movie.posterUrl ? (
                    <LazyImage src={movie.posterUrl} alt={movie.name} className="w-full h-full" />
                  ) : (
                    <Play className="w-8 h-8 text-muted-foreground/30 group-hover:text-primary/60 transition-colors" />
                  )}
                  <button onClick={(e) => { e.stopPropagation(); toggle(movie.id); }} className="absolute top-2 right-2 z-10">
                    <Star className={`w-4 h-4 ${isFavorite(movie.id) ? "text-primary fill-primary" : "text-muted-foreground/80"}`} />
                  </button>
                  {movie.rating && (
                    <span className="absolute top-2 left-2 text-[10px] bg-primary/80 text-primary-foreground px-1.5 py-0.5 rounded">★ {movie.rating}</span>
                  )}
                </div>
                <div className="p-2.5">
                  <p className="text-foreground text-xs font-medium truncate">{movie.name}</p>
                  <div className="flex items-center justify-between mt-1">
                    <span className="text-muted-foreground text-[10px] truncate">{movie.category}</span>
                    {movie.year && <span className="text-muted-foreground text-[10px]">{movie.year}</span>}
                  </div>
                </div>
              </FocusableTile>
            );

            // Splice an inline sponsored slot every AD_SLOT_EVERY items
            // (skipped for premium / expired-trial users).
            const shouldShowAd =
              adsEnabled && (idx + 1) % AD_SLOT_EVERY === 0;
            if (!shouldShowAd) return [tile];
            return [
              tile,
              <InlineAdSlot
                key={`ad-${idx}`}
                testId={`movies-inline-ad-${idx}`}
                onClick={() => void watchRewardAd()}
              />,
            ];
          })}
          {/* Infinite-scroll sentinel — sits inside the grid so the
              IntersectionObserver fires off the grid's own scrollport.
              Spans the full width so it always intersects regardless
              of which column the previous item ended on. */}
          {hasMore && (
            <div
              ref={sentinelRef}
              data-testid="movies-infinite-sentinel"
              style={{ gridColumn: "1 / -1", height: 1 }}
              aria-hidden
            />
          )}
        </FocusableSection>
      </div>

      <AnimatePresence>
        {playing && (
          <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
            className="fixed inset-0 z-50 bg-black/80 backdrop-blur-sm flex items-center justify-center p-4">
            <motion.div initial={{ scale: 0.95 }} animate={{ scale: 1 }} exit={{ scale: 0.95 }}
              className="relative w-full max-w-4xl glass-card rounded-2xl overflow-hidden">
              <button onClick={() => void closeMovie()} className="absolute top-3 right-3 z-10 w-8 h-8 rounded-full glass flex items-center justify-center">
                <X className="w-4 h-4 text-foreground" />
              </button>
              <div className="aspect-video bg-black">
                <VideoPlayer src={playing.streamUrl} poster={playing.posterUrl} isLive={false} contentId={playing.id} />
              </div>
              <div className="p-4">
                <p className="text-foreground text-sm font-medium">{playing.name}</p>
                <p className="text-muted-foreground text-xs">{playing.category} {playing.year && `• ${playing.year}`}</p>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </PageLayout>
  );
};

export default Movies;
