import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { qk } from "../lib/queryKeys";
import { Plus, Trash2 } from "lucide-react";
import { api, type Tag } from "../lib/api";
import { notify } from "../lib/notifications";
import { useScrollFade } from "../lib/useScrollFade";
import Modal from "./Modal";
import { useConfirm } from "./ConfirmProvider";
import { PopoverSurface, useAnchoredPopover } from "./AnchoredPopover";

// One editable row: rename in place (commit on Enter/blur), delete with a confirm, and a
// hover popover on the count listing the tagged channels (each a link that focuses it in the
// Channel manager). The popover rides the R8 platform, so the list's own scroll can't clip it and
// the cursor can travel the gap into it (safePolygon) without the old hand-rolled 150 ms timer.
function TagRow({
  tag,
  channels,
  onRename,
  onDelete,
  onPickChannel,
}: {
  tag: Tag;
  channels: { id: string; title: string }[];
  onRename: (name: string) => void;
  onDelete: () => void;
  onPickChannel: (name: string) => void;
}) {
  const { t } = useTranslation();
  const [name, setName] = useState(tag.name);
  const [open, setOpen] = useState(false);
  const popFade = useScrollFade();
  const commit = () => {
    const v = name.trim();
    if (v && v !== tag.name) onRename(v);
    else setName(tag.name);
  };
  const pop = useAnchoredPopover({
    open: open && channels.length > 0,
    onOpenChange: setOpen,
    mode: "hover",
    placement: "right-start",
    offset: 8,
    hoverDelay: { open: 0, close: 150 },
  });
  return (
    <div className="flex items-center gap-2">
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        onBlur={commit}
        onKeyDown={(e) => e.key === "Enter" && (e.target as HTMLInputElement).blur()}
        className="flex-1 min-w-0 bg-card border border-border rounded-md px-2 py-1.5 text-sm outline-none focus:border-accent"
      />
      <span
        ref={pop.refs.setReference}
        {...pop.getReferenceProps()}
        className={`text-xs text-muted tabular-nums shrink-0 ${
          channels.length
            ? "cursor-help underline decoration-dotted decoration-muted/40 underline-offset-2"
            : ""
        }`}
      >
        {t("tagManager.channels", { count: tag.channel_count })}
      </span>
      <button
        onClick={onDelete}
        title={t("tagManager.delete")}
        aria-label={t("tagManager.delete")}
        className="shrink-0 p-1.5 rounded-md text-muted hover:text-red-400 transition"
      >
        <Trash2 className="w-4 h-4" />
      </button>
      <PopoverSurface
        popover={pop}
        className="glass-menu w-56 rounded-xl p-1.5 animate-[popIn_0.16s_ease]"
      >
        <div className="text-[11px] uppercase tracking-wide text-muted px-2 py-1">
          {t("tagManager.onChannels")}
        </div>
        {/* Inner scroller so the scroll-fade mask rides the scrolling box, not the glass panel. */}
        <div
          ref={popFade.ref}
          style={popFade.style}
          className="max-h-72 overflow-y-auto no-scrollbar"
        >
          {channels.map((ch) => (
            <button
              key={ch.id}
              onClick={() => onPickChannel(ch.title)}
              className="w-full text-left text-sm px-2 py-1.5 rounded-md text-muted hover:text-fg hover:bg-card truncate transition"
            >
              {ch.title}
            </button>
          ))}
        </div>
      </PopoverSurface>
    </div>
  );
}

export default function TagManager({
  onClose,
  onFocusChannel,
}: {
  onClose: () => void;
  onFocusChannel: (name: string) => void;
}) {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const confirm = useConfirm();
  const listFade = useScrollFade();
  const [newName, setNewName] = useState("");
  const tagsQuery = useQuery({ queryKey: qk.tags(), queryFn: api.tags });
  const channelsQuery = useQuery({ queryKey: qk.channels(), queryFn: api.channels });
  const userTags = (tagsQuery.data ?? []).filter((tg) => !tg.system);
  const channelsForTag = (tagId: number) =>
    (channelsQuery.data ?? [])
      .filter((c) => c.tag_ids.includes(tagId))
      .map((c) => ({ id: c.id, title: c.title ?? c.id }));

  const invalidate = () => {
    qc.invalidateQueries({ queryKey: qk.tags() });
    qc.invalidateQueries({ queryKey: qk.channels() });
    qc.invalidateQueries({ queryKey: qk.feed() });
  };
  const create = useMutation({
    mutationFn: (name: string) => api.createTag({ name, category: "other" }),
    onSuccess: () => {
      setNewName("");
      invalidate();
    },
  });
  const rename = useMutation({
    mutationFn: (v: { id: number; name: string }) => api.updateTag(v.id, { name: v.name }),
    onSuccess: invalidate,
  });
  const del = useMutation({
    mutationFn: (v: { id: number; name: string }) => api.deleteTag(v.id),
    onSuccess: (_d, v) => {
      invalidate();
      notify({ level: "success", message: t("tagManager.deleted", { name: v.name }) });
    },
  });

  // Picking a channel from a tag's popover: close the dialog, then focus it in the manager.
  const pickChannel = (name: string) => {
    onClose();
    onFocusChannel(name);
  };

  return (
    <Modal title={t("tagManager.title")} onClose={onClose}>
      <div className="flex flex-col gap-2">
        {userTags.length === 0 ? (
          <p className="text-sm text-muted">{t("tagManager.empty")}</p>
        ) : (
          // Cap at ~8 rows tall, then scroll — the list can grow long.
          <div
            ref={listFade.ref}
            style={listFade.style}
            className="flex flex-col gap-2 max-h-[22rem] overflow-y-auto no-scrollbar pr-1"
          >
            {userTags.map((tag) => (
              <TagRow
                key={tag.id}
                tag={tag}
                channels={channelsForTag(tag.id)}
                onPickChannel={pickChannel}
                onRename={(name) => rename.mutate({ id: tag.id, name })}
                onDelete={async () => {
                  // Only confirm when the tag is actually in use; an unused tag deletes outright.
                  if (tag.channel_count > 0) {
                    const ok = await confirm({
                      title: t("tagManager.deleteTitle"),
                      message: t("tagManager.confirmDelete", {
                        name: tag.name,
                        count: tag.channel_count,
                      }),
                      confirmLabel: t("tagManager.delete"),
                      danger: true,
                    });
                    if (!ok) return;
                  }
                  del.mutate({ id: tag.id, name: tag.name });
                }}
              />
            ))}
          </div>
        )}
        <form
          onSubmit={(e) => {
            e.preventDefault();
            if (newName.trim()) create.mutate(newName.trim());
          }}
          className="flex items-center gap-2 mt-2 pt-3 border-t border-border"
        >
          <Plus className="w-4 h-4 text-muted shrink-0" />
          <input
            value={newName}
            onChange={(e) => setNewName(e.target.value)}
            placeholder={t("tagManager.newPlaceholder")}
            className="flex-1 min-w-0 bg-card border border-border rounded-md px-2 py-1.5 text-sm outline-none focus:border-accent"
          />
          <button
            type="submit"
            disabled={!newName.trim()}
            className="shrink-0 px-3 py-1.5 rounded-md border border-border text-sm text-muted enabled:hover:text-fg enabled:hover:border-accent disabled:opacity-40 transition"
          >
            {t("tagManager.add")}
          </button>
        </form>
      </div>
    </Modal>
  );
}
