import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { qk } from "../lib/queryKeys";
import { Check, ListPlus, Plus, Youtube } from "lucide-react";
import { api, type Playlist } from "../lib/api";
import { useScrollFade } from "../lib/useScrollFade";
import { playlistName } from "../lib/playlistName";
import { PopoverItem, PopoverSurface, useAnchoredPopover } from "./AnchoredPopover";

// A small anchored menu for toggling a video's membership in the user's playlists, with inline
// "new playlist" creation. Same shape as the channel tag editor (R8 S1's pilot): radio-style
// toggles plus a free-text creator, so it follows that file's two conventions — typeahead OFF and
// the input swallowing non-Escape keys, since character and arrow keys belong to the text field.
export default function AddToPlaylist({
  videoId,
  className,
}: {
  videoId: string;
  className?: string;
}) {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const fade = useScrollFade();
  const [open, setOpen] = useState(false);
  const [newName, setNewName] = useState("");
  const [busy, setBusy] = useState(false);

  const pop = useAnchoredPopover({
    open,
    onOpenChange: setOpen,
    offset: 6,
    // The menu holds a "new playlist" text field — keep typed chars and pointer-hover out of the
    // roving list so they don't steal the caret.
    hostsInput: true,
  });

  const membership = useQuery({
    queryKey: qk.playlistMembership(videoId),
    queryFn: () => api.playlists(videoId),
    enabled: open,
  });

  function refresh() {
    qc.invalidateQueries({ queryKey: qk.playlistMembership(videoId) });
    qc.invalidateQueries({ queryKey: qk.playlists() });
    // Also invalidate every open/cached playlist detail (["playlist", id]) so the
    // Playlists page reflects the add/remove when navigated to, not only after F5.
    qc.invalidateQueries({ queryKey: qk.playlist() });
  }

  async function toggle(pl: Playlist) {
    if (busy) return;
    setBusy(true);
    try {
      if (pl.has_video) await api.removeFromPlaylist(pl.id, videoId);
      else await api.addToPlaylist(pl.id, videoId);
      refresh();
    } finally {
      setBusy(false);
    }
  }

  async function createAndAdd() {
    const name = newName.trim();
    if (!name || busy) return;
    setBusy(true);
    try {
      const pl = await api.createPlaylist(name);
      await api.addToPlaylist(pl.id, videoId);
      setNewName("");
      refresh();
    } finally {
      setBusy(false);
    }
  }

  // All of the user's playlists are add targets, including YouTube-linked ones — adding
  // marks them dirty, and a later "Sync to YouTube" pushes the change back.
  const lists = membership.data ?? [];

  return (
    <>
      <button
        ref={pop.refs.setReference}
        {...pop.getReferenceProps({
          // The trigger sits on a feed card that opens the player on click, so the toggle must not
          // reach it.
          onClick: (e) => {
            e.preventDefault();
            e.stopPropagation();
          },
        })}
        title={t("playlists.addToPlaylist")}
        aria-label={t("playlists.addToPlaylist")}
        className={className ?? "p-1.5 rounded-md hover:bg-surface text-muted hover:text-fg"}
      >
        <ListPlus className="w-4 h-4" />
      </button>

      <PopoverSurface popover={pop} className="glass-menu w-60 rounded-xl p-2 shadow-2xl">
        {/* A React portal still propagates events up the REACT tree, so a click inside this panel
            would otherwise reach the feed card that hosts the trigger and start playback. */}
        <div onClick={(e) => e.stopPropagation()}>
          <div className="text-xs text-muted px-1.5 pb-1.5">{t("playlists.addToPlaylist")}</div>
          <div
            ref={fade.ref}
            style={fade.style}
            aria-busy={busy}
            className="max-h-56 overflow-y-auto no-scrollbar"
          >
            {lists.length === 0 && !membership.isLoading && (
              <div className="text-xs text-muted px-1.5 py-2">{t("playlists.noneYet")}</div>
            )}
            {lists.map((pl) => (
              <PopoverItem
                key={pl.id}
                // A video can sit in several playlists at once — checkboxes, not one choice.
                role="menuitemcheckbox"
                checked={pl.has_video}
                onSelect={() => toggle(pl)}
                // NOT `disabled={busy}`: the native disabled attribute would blur the focused item to
                // <body> mid-request and permanently kill roving focus (useListNavigation listens on
                // the floating element only). `toggle()` already no-ops while busy, so re-entrancy is
                // guarded without touching focus; `aria-busy` on the list conveys the pending state.
                label={playlistName(pl, t)}
                className="w-full flex items-center gap-2 text-sm px-1.5 py-1.5 rounded-lg text-fg outline-none transition hover:bg-card/60 data-[active]:bg-[color-mix(in_srgb,var(--accent)_24%,transparent)]"
              >
                <span
                  className={`grid place-items-center w-4 h-4 rounded border ${
                    pl.has_video ? "bg-accent border-accent text-accent-fg" : "border-border"
                  }`}
                >
                  {pl.has_video && <Check className="w-3 h-3" />}
                </span>
                <span className="truncate flex-1 text-left">{playlistName(pl, t)}</span>
                {(pl.source === "youtube" || pl.yt_playlist_id) && (
                  <Youtube className="w-3 h-3 shrink-0 text-muted" />
                )}
              </PopoverItem>
            ))}
          </div>
          <div className="flex items-center gap-1.5 border-t border-border mt-1.5 pt-1.5">
            <Plus className="w-3.5 h-3.5 text-muted shrink-0" />
            <input
              value={newName}
              onChange={(e) => setNewName(e.target.value)}
              onKeyDown={(e) => {
                // Escape bubbles to the popover's dismiss; every other key is text editing here and
                // must not reach the surrounding menu's list navigation.
                if (e.key === "Escape") return;
                e.stopPropagation();
                if (e.key === "Enter") {
                  e.preventDefault();
                  void createAndAdd();
                }
              }}
              placeholder={t("playlists.newPlaylist")}
              className="flex-1 min-w-0 bg-card border border-border rounded-md px-2 py-1 text-xs outline-none focus:border-accent"
            />
          </div>
        </div>
      </PopoverSurface>
    </>
  );
}
