import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
import { ArrowLeft, Film, Search, Tv2 } from "lucide-react";
import { api, type FeedFilters, type PlexCard } from "../lib/api";
import { notify } from "../lib/notifications";
import { useDebounced } from "../lib/useDebounced";

// Plex mode of the feed: browse/search the mirrored Plex library as feed-style cards, drill from a
// show into seasons/episodes. Rendered by App in place of <Feed> when filters.librarySource==="plex"
// (so the video-feed hooks never run in Plex mode). Playback lands in P2 — for now a card just
// announces it; shows drill down. Self-contained: its own library scope + search + sort + paging.

type Props = {
  filters: FeedFilters;
  setFilters: (f: FeedFilters) => void;
};

const PAGE = 40;

function secs(n?: number | null): string {
  if (!n) return "";
  const h = Math.floor(n / 3600);
  const m = Math.floor((n % 3600) / 60);
  return h ? `${h}h ${m}m` : `${m}m`;
}

export default function PlexBrowse({ filters, setFilters }: Props) {
  const { t } = useTranslation();
  const libsQ = useQuery({ queryKey: ["plex-libraries"], queryFn: api.plexLibraries });
  const libs = useMemo(() => libsQ.data?.libraries ?? [], [libsQ.data]);

  const [library, setLibrary] = useState<string | null>(null);
  const [q, setQ] = useState("");
  const [sort, setSort] = useState("added");
  const [openShow, setOpenShow] = useState<string | null>(null);
  const dq = useDebounced(q.trim(), 350);

  // Default to the first library once loaded.
  useEffect(() => {
    if (library === null && libs.length) setLibrary(libs[0].key);
  }, [libs, library]);

  const activeLib = libs.find((l) => l.key === library);

  const browseQ = useInfiniteQuery({
    queryKey: ["plex-browse", library, dq, sort],
    enabled: !!library && !openShow,
    initialPageParam: 0,
    queryFn: ({ pageParam }) =>
      api.plexBrowse({ library: library!, q: dq || undefined, sort, offset: pageParam as number, limit: PAGE }),
    getNextPageParam: (last) => {
      const seen = last.offset + last.items.length;
      return seen < last.total ? seen : undefined;
    },
  });

  const items = browseQ.data?.pages.flatMap((p) => p.items) ?? [];
  const total = browseQ.data?.pages[0]?.total ?? 0;

  function exitPlex() {
    setFilters({ ...filters, librarySource: "organic", q: "" });
  }
  function onPlay(card: PlexCard) {
    // P2 wires the real player; announce for now so the flow is visible in P1.
    notify({ level: "info", message: t("plex.playerSoon", { title: card.title }) });
  }
  function onCard(card: PlexCard) {
    if (card.type === "show") setOpenShow(card.id);
    else onPlay(card);
  }

  if (openShow) {
    return <PlexShowView showId={openShow} onBack={() => setOpenShow(null)} onPlay={onPlay} onExit={exitPlex} />;
  }

  return (
    <div className="p-4 max-w-[1600px] mx-auto">
      {/* Toolbar: back-to-YouTube, library scope, search, sort */}
      <div className="flex flex-wrap items-center gap-2 mb-4">
        <button
          onClick={exitPlex}
          className="glass-card glass-hover inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs"
          title={t("plex.backToFeed")}
        >
          <ArrowLeft className="w-4 h-4" />
          {t("plex.backToFeed")}
        </button>
        <span className="mx-1 h-5 w-px bg-border" aria-hidden="true" />
        <div className="inline-flex items-center gap-1">
          {libs.map((l) => (
            <button
              key={l.key}
              onClick={() => setLibrary(l.key)}
              className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs transition ${
                l.key === library ? "bg-accent text-white" : "glass-card glass-hover"
              }`}
            >
              {l.kind === "movie" ? <Film className="w-3.5 h-3.5" /> : <Tv2 className="w-3.5 h-3.5" />}
              {l.title}
              <span className="opacity-60">{l.count.toLocaleString()}</span>
            </button>
          ))}
        </div>
        <div className="relative ml-auto">
          <Search className="w-4 h-4 absolute left-2.5 top-1/2 -translate-y-1/2 text-muted" />
          <input
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder={t("plex.searchPlaceholder")}
            className="bg-card border border-border rounded-lg pl-8 pr-3 py-1.5 text-sm w-56 outline-none focus:border-accent"
          />
        </div>
        <select
          value={sort}
          onChange={(e) => setSort(e.target.value)}
          className="bg-card border border-border rounded-lg px-2 py-1.5 text-xs outline-none focus:border-accent"
        >
          <option value="added">{t("plex.sort.added")}</option>
          <option value="title">{t("plex.sort.title")}</option>
        </select>
      </div>

      <p className="text-xs text-muted mb-3">
        {dq ? t("plex.searchCount", { count: total }) : t("plex.count", { count: total })}
      </p>

      {browseQ.isLoading ? (
        <p className="text-muted text-sm">{t("plex.loading")}</p>
      ) : items.length === 0 ? (
        <p className="text-muted text-sm">{t("plex.empty")}</p>
      ) : (
        <div className="grid grid-cols-[repeat(auto-fill,minmax(150px,1fr))] gap-3">
          {items.map((c) => (
            <PlexPosterCard key={c.id} card={c} onClick={() => onCard(c)} />
          ))}
        </div>
      )}

      {browseQ.hasNextPage && (
        <div className="flex justify-center mt-5">
          <button
            onClick={() => browseQ.fetchNextPage()}
            disabled={browseQ.isFetchingNextPage}
            className="glass-card glass-hover px-4 py-2 rounded-xl text-sm disabled:opacity-50"
          >
            {browseQ.isFetchingNextPage ? t("plex.loading") : t("plex.loadMore")}
          </button>
        </div>
      )}
    </div>
  );
}

const PLAYABLE_TINT: Record<string, string> = {
  direct: "bg-emerald-500",
  remux: "bg-amber-500",
  transcode: "bg-orange-600",
};

function PlexPosterCard({ card, onClick }: { card: PlexCard; onClick: () => void }) {
  const { t } = useTranslation();
  const inProgress = (card.position_seconds ?? 0) > 0 && card.status !== "watched";
  const pct =
    inProgress && card.duration_seconds
      ? Math.min(100, Math.round(((card.position_seconds ?? 0) / card.duration_seconds) * 100))
      : 0;
  return (
    <button onClick={onClick} className="group text-left">
      <div className="relative aspect-[2/3] rounded-xl overflow-hidden bg-card border border-border">
        <img
          src={card.thumb}
          alt=""
          loading="lazy"
          className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200"
        />
        {card.status === "watched" && (
          <span className="absolute top-1.5 right-1.5 text-[10px] bg-black/70 text-white px-1.5 py-0.5 rounded">
            {t("plex.watched")}
          </span>
        )}
        {card.type === "show" && card.season_count != null && (
          <span className="absolute bottom-1.5 left-1.5 text-[10px] bg-black/70 text-white px-1.5 py-0.5 rounded">
            {t("plex.seasons", { count: card.season_count })}
          </span>
        )}
        {card.playable && (
          <span
            className={`absolute top-1.5 left-1.5 w-2 h-2 rounded-full ${PLAYABLE_TINT[card.playable] ?? "bg-gray-400"}`}
            title={t(`plex.playable.${card.playable}`)}
          />
        )}
        {pct > 0 && (
          <div className="absolute bottom-0 inset-x-0 h-1 bg-black/40">
            <div className="h-full bg-accent" style={{ width: `${pct}%` }} />
          </div>
        )}
      </div>
      <div className="mt-1.5 text-sm font-medium line-clamp-2 leading-tight">{card.title}</div>
      <div className="text-xs text-muted">
        {[card.year, secs(card.duration_seconds)].filter(Boolean).join(" · ")}
      </div>
    </button>
  );
}

function PlexShowView({
  showId,
  onBack,
  onPlay,
  onExit,
}: {
  showId: string;
  onBack: () => void;
  onPlay: (c: PlexCard) => void;
  onExit: () => void;
}) {
  const { t } = useTranslation();
  const q = useQuery({ queryKey: ["plex-show", showId], queryFn: () => api.plexShow(showId) });
  const d = q.data;

  return (
    <div className="p-4 max-w-[1200px] mx-auto">
      <div className="flex items-center gap-2 mb-4">
        <button
          onClick={onBack}
          className="glass-card glass-hover inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs"
        >
          <ArrowLeft className="w-4 h-4" />
          {t("plex.backToLibrary")}
        </button>
        <button onClick={onExit} className="text-xs text-muted hover:text-fg ml-1">
          {t("plex.backToFeed")}
        </button>
      </div>

      {q.isLoading || !d ? (
        <p className="text-muted text-sm">{t("plex.loading")}</p>
      ) : (
        <>
          <div className="flex gap-4 mb-6">
            <img
              src={d.show.thumb}
              alt=""
              className="w-32 sm:w-40 aspect-[2/3] object-cover rounded-xl border border-border shrink-0"
            />
            <div className="min-w-0">
              <h1 className="text-xl font-semibold">{d.show.title}</h1>
              {d.show.year && <p className="text-sm text-muted">{d.show.year}</p>}
              {d.show.summary && (
                <p className="text-sm text-muted mt-2 line-clamp-6 leading-relaxed">{d.show.summary}</p>
              )}
            </div>
          </div>

          {d.seasons.map((se) => (
            <div key={se.id} className="mb-6">
              <h2 className="text-sm font-semibold mb-2">{se.title}</h2>
              <div className="flex flex-col divide-y divide-border/60">
                {se.episodes.map((ep) => {
                  const inProgress = (ep.position_seconds ?? 0) > 0 && ep.status !== "watched";
                  return (
                    <button
                      key={ep.id}
                      onClick={() => onPlay(ep)}
                      className="flex items-center gap-3 py-2 text-left group"
                    >
                      <div className="relative w-28 aspect-video rounded-lg overflow-hidden bg-card border border-border shrink-0">
                        <img src={ep.thumb} alt="" loading="lazy" className="w-full h-full object-cover" />
                        {ep.status === "watched" && (
                          <span className="absolute top-1 right-1 text-[9px] bg-black/70 text-white px-1 rounded">
                            ✓
                          </span>
                        )}
                        {inProgress && <div className="absolute bottom-0 inset-x-0 h-0.5 bg-accent" />}
                      </div>
                      <div className="min-w-0 flex-1">
                        <div className="text-sm font-medium truncate">
                          <span className="text-muted mr-1.5">{ep.episode_number}.</span>
                          {ep.title}
                        </div>
                        {ep.summary && (
                          <div className="text-xs text-muted line-clamp-2 mt-0.5">{ep.summary}</div>
                        )}
                        <div className="text-[11px] text-muted mt-0.5">{secs(ep.duration_seconds)}</div>
                      </div>
                    </button>
                  );
                })}
              </div>
            </div>
          ))}
        </>
      )}
    </div>
  );
}
