import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Search, Star, Clapperboard, ChevronDown, RefreshCw, Loader2, X, Play, Loader } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
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 { useProfiles } from "@/hooks/useProfiles";
import { useSeries, useReloadPlaylist } from "@/hooks/useXtreamData";
import { useFavorites } from "@/hooks/useFavorites";
import { xtreamApi } from "@/lib/xtream";
import type { Series } 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";

const AD_SLOT_EVERY = 6;
const PAGE_SIZE = 50;

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

  const [search, setSearch] = useState("");
  const [selectedCategory, setSelectedCategory] = useState("All");
  const [openSeries, setOpenSeries] = useState<Series | null>(null);
  const [episodeUrl, setEpisodeUrl] = useState<string | null>(null);
  const [visibleCount, setVisibleCount] = useState(PAGE_SIZE);

  // FEATURE (2026-01): banner is now mounted GLOBALLY in App.tsx
  // via useGlobalBanner(). No per-page wiring needed.
  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.
  const { watchAd: watchRewardAd } = useAdFreeUnlock({ adsToWatch: 3, hoursPerUnlock: 1 });

  const playEpisode = (
    url: string,
    _epId?: string | number,
    _ext?: string,
  ) => {
    // UX fix (2026-06): open player instantly on tap to remove delay.
    setEpisodeUrl(url);
  };

  const closeSeries = async () => {
    const wasPlaying = !!episodeUrl;
    setOpenSeries(null);
    setEpisodeUrl(null);
    // Fire post-exit interstitial only when the user was actually
    // watching an episode (not just browsing the modal).
    if (wasPlaying) await fireInterstitial();
  };

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

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

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

  const visibleSeries = filtered.slice(0, visibleCount);
  const hasMore = visibleCount < filtered.length;

  // FEATURE (2026-01) — infinite scroll. See Movies.tsx for rationale.
  const { sentinelRef } = useInfiniteScroll({
    hasMore,
    onLoadMore: () => setVisibleCount((c) => c + PAGE_SIZE),
  });

  const seriesInfoQuery = useQuery({
    queryKey: ["xtream", effectiveProfile?.id, "series-info", openSeries?.id],
    queryFn: () => xtreamApi.getSeriesInfo(effectiveProfile!, openSeries!.id),
    enabled: !!openSeries && !!effectiveProfile,
  });

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

  const episodesBySeason: Record<string, any[]> = seriesInfoQuery.data?.episodes ?? {};

  return (
    <PageLayout title={t("series.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("series.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(effectiveProfile!.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("series.failedLoad")}</p>}

        <FocusableSection
          autoFocus
          focusKey="series-grid"
          className="flex-1 min-h-0 overflow-y-auto gap-2 grid"
          style={{
            gridTemplateColumns: "repeat(auto-fill, minmax(110px, 1fr))",
            gridAutoRows: "max-content",
            // Edge-to-edge: PageLayout already reserves the bottom
            // banner height. Only add the device safe-area inset.
            paddingBottom: "env(safe-area-inset-bottom, 0px)",
            overscrollBehavior: "contain",
            touchAction: "pan-y",
          }}
        >
          {visibleSeries.flatMap((s, idx) => {
            const tile = (
              <FocusableTile
                key={s.id}
                focusKey={`series-${s.id}`}
                onEnter={() => setOpenSeries(s)}
                onClick={() => setOpenSeries(s)}
                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" }}
                >
                  {s.posterUrl ? (
                    <img src={s.posterUrl} alt={s.name} loading="lazy" decoding="async" className="w-full h-full object-cover"
                      onError={(e) => (e.currentTarget.style.display = "none")} />
                  ) : (
                    <Clapperboard className="w-8 h-8 text-muted-foreground/30 group-hover:text-primary/60 transition-colors" />
                  )}
                  <button onClick={(e) => { e.stopPropagation(); toggle(s.id); }} className="absolute top-2 right-2 z-10">
                    <Star className={`w-4 h-4 ${isFavorite(s.id) ? "text-primary fill-primary" : "text-muted-foreground/80"}`} />
                  </button>
                  {s.rating && (
                    <span className="absolute top-2 left-2 text-[10px] bg-primary/80 text-primary-foreground px-1.5 py-0.5 rounded">★ {s.rating}</span>
                  )}
                </div>
                <div className="p-2.5">
                  <p className="text-foreground text-xs font-medium truncate">{s.name}</p>
                  <span className="text-muted-foreground text-[10px] truncate block">{s.category}</span>
                </div>
              </FocusableTile>
            );
            const shouldShowAd = adsEnabled && (idx + 1) % AD_SLOT_EVERY === 0;
            if (!shouldShowAd) return [tile];
            return [
              tile,
              <InlineAdSlot
                key={`ad-${idx}`}
                testId={`series-inline-ad-${idx}`}
                onClick={() => void watchRewardAd()}
              />,
            ];
          })}
          {/* Infinite-scroll sentinel — see Movies.tsx for rationale. */}
          {hasMore && (
            <div
              ref={sentinelRef}
              data-testid="series-infinite-sentinel"
              style={{ gridColumn: "1 / -1", height: 1 }}
              aria-hidden
            />
          )}
        </FocusableSection>
      </div>

      {/* Series detail modal */}
      <AnimatePresence>
        {openSeries && (
          <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"
            onClick={() => void closeSeries()}>
            <motion.div initial={{ scale: 0.95 }} animate={{ scale: 1 }} exit={{ scale: 0.95 }}
              onClick={(e) => e.stopPropagation()}
              className="relative w-full max-w-4xl max-h-[90vh] glass-card rounded-2xl overflow-hidden flex flex-col">
              <button onClick={() => void closeSeries()} 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>

              {episodeUrl ? (
                <div className="aspect-video bg-black">
                  <VideoPlayer src={episodeUrl} />
                </div>
              ) : (
                <div className="p-5 flex gap-4 border-b border-border">
                  {openSeries.posterUrl && (
                    <img src={openSeries.posterUrl} alt="" className="w-24 h-36 object-cover rounded-lg" />
                  )}
                  <div>
                    <h2 className="text-foreground text-lg font-medium">{openSeries.name}</h2>
                    <p className="text-muted-foreground text-xs mb-1">{openSeries.category}</p>
                    {openSeries.rating && <p className="text-primary text-xs">★ {openSeries.rating}</p>}
                    {openSeries.plot && <p className="text-muted-foreground text-xs mt-2 line-clamp-3">{openSeries.plot}</p>}
                  </div>
                </div>
              )}

              <div className="flex-1 overflow-y-auto p-4 space-y-4">
                {seriesInfoQuery.isLoading && (
                  <div className="flex justify-center py-6"><Loader className="w-5 h-5 animate-spin text-primary" /></div>
                )}
                {Object.entries(episodesBySeason).map(([season, eps]) => (
                  <FocusableSection key={season} focusKey={`season-${season}`}>
                    <h3 className="text-foreground text-sm font-medium mb-2">{t("series.season", { n: season })}</h3>
                    <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
                      {eps.map((ep: any) => {
                        const url = xtreamApi.buildSeriesEpisodeUrl(effectiveProfile!, ep.id, ep.container_extension || "mp4");
                        return (
                          <FocusableButton
                            key={ep.id}
                            focusKey={`ep-${ep.id}`}
                            onEnter={() => void playEpisode(url, ep.id, ep.container_extension)}
                            onClick={() => void playEpisode(url, ep.id, ep.container_extension)}
                            className="flex items-center gap-2 glass rounded-lg px-3 py-2 hover:border-primary/30 transition-all text-left border-transparent"
                          >
                            <Play className="w-3 h-3 text-primary shrink-0" />
                            <span className="text-foreground text-xs truncate">{t("series.episodePrefix", { n: ep.episode_num })}: {ep.title}</span>
                          </FocusableButton>
                        );
                      })}
                    </div>
                  </FocusableSection>
                ))}
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </PageLayout>
  );
};

export default SeriesPage;
