import { useEffect, type ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { useQuery } from "@tanstack/react-query";
import { ChevronRight, Film, SlidersHorizontal, Tv2, X } from "lucide-react";
import { api, EMPTY_PLEX_FILTERS, plexFilterCount, type PlexFilters } from "../lib/api";

// The Plex module's left filter column (mirrors the feed Sidebar's shell). Movie libraries get the
// full metadata filter set (genre / rating / year / duration / added / content rating + the
// director/actor/studio chips set by clicking the info page); shows keep library + sort only. State
// is owned by App (per-account persisted). Facets (available genres/ratings + bounds) come from the
// backend so the sidebar only offers what the library actually contains.

type Props = {
  library: string;
  setLibrary: (v: string) => void;
  show: string;
  setShow: (v: string) => void;
  sort: string;
  setSort: (v: string) => void;
  filters: PlexFilters;
  setFilters: (f: PlexFilters) => void;
  collapsed: boolean;
  onToggleCollapse: () => void;
};

const SHOW_OPTS = ["all", "unwatched", "in_progress", "watched"] as const;
const MOVIE_SORTS = ["added", "release", "year", "rating", "duration", "title"] as const;
const SHOW_SORTS = ["added", "title"] as const;
const RATING_STEPS = [5, 6, 7, 8, 9];
const ADDED_OPTS = ["24h", "1w", "1m", "6m", "1y"] as const;
// Duration buckets → [minSeconds|null, maxSeconds|null].
const DURATION_BUCKETS: { key: string; min: number | null; max: number | null }[] = [
  { key: "short", min: null, max: 90 * 60 },
  { key: "mid", min: 90 * 60, max: 120 * 60 },
  { key: "long", min: 120 * 60, max: null },
];

export default function PlexSidebar({
  library,
  setLibrary,
  show,
  setShow,
  sort,
  setSort,
  filters,
  setFilters,
  collapsed,
  onToggleCollapse,
}: Props) {
  const { t } = useTranslation();
  const libsQ = useQuery({ queryKey: ["plex-libraries"], queryFn: api.plexLibraries });
  const libs = libsQ.data?.libraries ?? [];
  const activeLib = libs.find((l) => l.key === library);
  const isMovieLib = activeLib?.kind === "movie";

  const facetsQ = useQuery({
    queryKey: ["plex-facets", library],
    queryFn: () => api.plexFacets(library),
    enabled: !!library && isMovieLib,
  });
  const facets = facetsQ.data;

  // Default to the first library once loaded (or if the stored one vanished).
  useEffect(() => {
    if (libs.length && !libs.some((l) => l.key === library)) setLibrary(libs[0].key);
  }, [libs, library, setLibrary]);

  const fCount = isMovieLib ? plexFilterCount(filters) : 0;
  const activeCount =
    fCount + (show !== "all" && isMovieLib ? 1 : 0) + (sort !== "added" ? 1 : 0);
  const anyActive = activeCount > 0;

  const patch = (p: Partial<PlexFilters>) => setFilters({ ...filters, ...p });
  const toggleIn = (arr: string[], v: string) =>
    arr.includes(v) ? arr.filter((x) => x !== v) : [...arr, v];
  const clearAll = () => {
    setFilters(EMPTY_PLEX_FILTERS);
    setShow("all");
    setSort("added");
  };

  const sorts = isMovieLib ? MOVIE_SORTS : SHOW_SORTS;
  const durBucketKey = DURATION_BUCKETS.find(
    (b) => (filters.durationMin ?? null) === b.min && (filters.durationMax ?? null) === b.max,
  )?.key;

  if (collapsed) {
    return (
      <aside className="hidden md:flex w-[46px] shrink-0 flex-col items-center gap-2 border-r border-border bg-surface/40 py-3">
        <button
          onClick={onToggleCollapse}
          title={t("sidebar.expandPanel")}
          aria-label={t("sidebar.expandPanel")}
          className="p-1 rounded-md text-muted hover:text-fg hover:bg-card transition"
        >
          <ChevronRight className="w-4 h-4" />
        </button>
        <button
          onClick={onToggleCollapse}
          title={t("sidebar.filters")}
          className="relative p-2 rounded-lg text-muted hover:text-fg hover:bg-card transition"
        >
          <SlidersHorizontal className="w-5 h-5" />
          {activeCount > 0 && (
            <span className="absolute -top-1 -right-1 min-w-[16px] h-4 px-1 rounded-full bg-accent text-accent-fg text-[10px] font-bold leading-none grid place-items-center ring-2 ring-bg">
              {activeCount}
            </span>
          )}
        </button>
      </aside>
    );
  }

  return (
    <aside className="hidden md:block w-64 shrink-0 border-r border-border bg-surface/40 overflow-y-auto p-4 space-y-4">
      {/* Library scope */}
      <Section label={t("plex.filter.library")}>
        <div className="flex flex-col gap-1">
          {libs.map((l) => (
            <button
              key={l.key}
              onClick={() => setLibrary(l.key)}
              className={`inline-flex items-center gap-2 px-2.5 py-1.5 rounded-lg text-sm transition ${
                l.key === library ? "bg-accent text-accent-fg" : "glass-card glass-hover"
              }`}
            >
              {l.kind === "movie" ? <Film className="w-4 h-4" /> : <Tv2 className="w-4 h-4" />}
              <span className="flex-1 text-left truncate">{l.title}</span>
              <span className="opacity-60 text-xs">{l.count.toLocaleString()}</span>
            </button>
          ))}
        </div>
      </Section>

      {anyActive && (
        <button
          onClick={clearAll}
          className="w-full inline-flex items-center justify-center gap-1.5 rounded-lg border border-border px-2.5 py-1.5 text-xs text-muted hover:border-accent hover:text-accent transition"
        >
          <X className="w-3.5 h-3.5" />
          {t("plex.filter.clearAll")} ({activeCount})
        </button>
      )}

      {/* Watch state (movie libraries only) */}
      {isMovieLib && (
        <Section label={t("plex.filter.show")}>
          <ChipRow>
            {SHOW_OPTS.map((s) => (
              <Chip key={s} active={show === s} onClick={() => setShow(s)}>
                {t(`plex.filter.showOpt.${s}`)}
              </Chip>
            ))}
          </ChipRow>
        </Section>
      )}

      {/* Sort + direction */}
      <Section label={t("plex.filter.sort")}>
        <ChipRow>
          {sorts.map((s) => (
            <Chip key={s} active={sort === s} onClick={() => setSort(s)}>
              {t(`plex.sort.${s}`)}
            </Chip>
          ))}
        </ChipRow>
        <div className="mt-1.5 flex gap-1">
          {(["desc", "asc"] as const).map((d) => (
            <Chip key={d} active={(filters.sortDir ?? "desc") === d} onClick={() => patch({ sortDir: d })}>
              {t(`plex.filter.dir.${d}`)}
            </Chip>
          ))}
        </div>
      </Section>

      {/* Metadata filters (movie libraries only) */}
      {isMovieLib && (
        <>
          {/* Active people / studios — set by clicking the info page (stackable). */}
          {filters.directors.length + filters.actors.length + filters.studios.length > 0 && (
            <Section label={t("plex.filter.active")}>
              <div className="flex flex-wrap gap-1.5">
                {filters.directors.map((d) => (
                  <RemovableChip
                    key={`d:${d}`}
                    label={d}
                    onRemove={() => patch({ directors: filters.directors.filter((x) => x !== d) })}
                  />
                ))}
                {filters.actors.map((a) => (
                  <RemovableChip
                    key={`a:${a}`}
                    label={a}
                    onRemove={() => patch({ actors: filters.actors.filter((x) => x !== a) })}
                  />
                ))}
                {filters.studios.map((s) => (
                  <RemovableChip
                    key={`s:${s}`}
                    label={s}
                    onRemove={() => patch({ studios: filters.studios.filter((x) => x !== s) })}
                  />
                ))}
              </div>
            </Section>
          )}

          {/* IMDb rating min */}
          <Section label={t("plex.filter.rating")}>
            <ChipRow>
              <Chip active={filters.ratingMin == null} onClick={() => patch({ ratingMin: null })}>
                {t("plex.filter.any")}
              </Chip>
              {RATING_STEPS.map((r) => (
                <Chip key={r} active={filters.ratingMin === r} onClick={() => patch({ ratingMin: r })}>
                  {r}+
                </Chip>
              ))}
            </ChipRow>
          </Section>

          {/* Genres (from facets) + Any/All when more than one is picked */}
          {facets && facets.genres.length > 0 && (
            <Section label={t("plex.filter.genre")}>
              {filters.genres.length > 1 && (
                <div className="mb-1.5 inline-flex overflow-hidden rounded-lg border border-border text-[11px]">
                  {(["any", "all"] as const).map((m) => (
                    <button
                      key={m}
                      onClick={() => patch({ genreMode: m })}
                      className={`px-2 py-0.5 transition ${
                        (filters.genreMode ?? "any") === m
                          ? "bg-accent text-accent-fg"
                          : "text-muted hover:bg-surface"
                      }`}
                    >
                      {t(`plex.filter.match.${m}`)}
                    </button>
                  ))}
                </div>
              )}
              <ChipRow>
                {facets.genres.map((g) => (
                  <Chip
                    key={g.value}
                    active={filters.genres.includes(g.value)}
                    onClick={() => patch({ genres: toggleIn(filters.genres, g.value) })}
                  >
                    {g.value}
                  </Chip>
                ))}
              </ChipRow>
            </Section>
          )}

          {/* Year range */}
          <Section label={t("plex.filter.year")}>
            <div className="flex items-center gap-2">
              <NumberInput
                value={filters.yearMin ?? null}
                placeholder={facets?.year_min ?? undefined}
                onChange={(v) => patch({ yearMin: v })}
              />
              <span className="text-muted text-xs">–</span>
              <NumberInput
                value={filters.yearMax ?? null}
                placeholder={facets?.year_max ?? undefined}
                onChange={(v) => patch({ yearMax: v })}
              />
            </div>
          </Section>

          {/* Duration buckets */}
          <Section label={t("plex.filter.duration")}>
            <ChipRow>
              <Chip
                active={!durBucketKey && filters.durationMin == null && filters.durationMax == null}
                onClick={() => patch({ durationMin: null, durationMax: null })}
              >
                {t("plex.filter.any")}
              </Chip>
              {DURATION_BUCKETS.map((b) => (
                <Chip
                  key={b.key}
                  active={durBucketKey === b.key}
                  onClick={() => patch({ durationMin: b.min, durationMax: b.max })}
                >
                  {t(`plex.filter.durationOpt.${b.key}`)}
                </Chip>
              ))}
            </ChipRow>
          </Section>

          {/* Added to Plex */}
          <Section label={t("plex.filter.added")}>
            <ChipRow>
              <Chip active={!filters.addedWithin} onClick={() => patch({ addedWithin: "" })}>
                {t("plex.filter.any")}
              </Chip>
              {ADDED_OPTS.map((a) => (
                <Chip key={a} active={filters.addedWithin === a} onClick={() => patch({ addedWithin: a })}>
                  {t(`plex.filter.addedOpt.${a}`)}
                </Chip>
              ))}
            </ChipRow>
          </Section>

          {/* Content rating (from facets) */}
          {facets && facets.content_ratings.length > 0 && (
            <Section label={t("plex.filter.contentRating")}>
              <ChipRow>
                {facets.content_ratings.map((c) => (
                  <Chip
                    key={c.value}
                    active={filters.contentRatings.includes(c.value)}
                    onClick={() => patch({ contentRatings: toggleIn(filters.contentRatings, c.value) })}
                  >
                    {c.value}
                  </Chip>
                ))}
              </ChipRow>
            </Section>
          )}
        </>
      )}
    </aside>
  );
}

function Section({ label, children }: { label: string; children: ReactNode }) {
  return (
    <div>
      <div className="text-[11px] uppercase tracking-wide text-muted mb-1.5">{label}</div>
      {children}
    </div>
  );
}

function ChipRow({ children }: { children: ReactNode }) {
  return <div className="flex flex-wrap gap-1">{children}</div>;
}

function Chip({
  active,
  onClick,
  children,
}: {
  active: boolean;
  onClick: () => void;
  children: ReactNode;
}) {
  return (
    <button
      onClick={onClick}
      className={`px-2.5 py-1 rounded-full text-xs transition ${
        active ? "bg-accent text-accent-fg" : "glass-card glass-hover"
      }`}
    >
      {children}
    </button>
  );
}

function RemovableChip({ label, onRemove }: { label: string; onRemove: () => void }) {
  return (
    <span className="inline-flex items-center gap-1 rounded-full bg-accent/15 text-accent px-2 py-1 text-xs">
      <span className="truncate max-w-[9rem]">{label}</span>
      <button onClick={onRemove} className="hover:opacity-70" aria-label="remove">
        <X className="w-3 h-3" />
      </button>
    </span>
  );
}

function NumberInput({
  value,
  placeholder,
  onChange,
}: {
  value: number | null;
  placeholder?: number;
  onChange: (v: number | null) => void;
}) {
  return (
    <input
      type="number"
      inputMode="numeric"
      value={value ?? ""}
      placeholder={placeholder != null ? String(placeholder) : ""}
      onChange={(e) => {
        const n = e.target.value === "" ? null : Number(e.target.value);
        onChange(n != null && Number.isFinite(n) ? n : null);
      }}
      className="w-20 rounded-lg border border-border bg-card px-2 py-1 text-sm tabular-nums focus:border-accent focus:outline-none"
    />
  );
}
