"use client";

import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Repeat2, Quote, Undo2 } from "lucide-react";
import { firework } from "@/lib/particles";
import { sfx } from "@/lib/sfx";
import type { Post } from "@/lib/types";

/**
 * The repost button and its menu.
 *
 * The menu is rendered into the body rather than inside the post, so an
 * ancestor with hidden overflow can't clip it — a card in a scrolling feed
 * usually has one.
 */
export function RepostMenu({
  post,
  onReposted,
  onQuote,
}: {
  post: Post;
  /** Called with the new count when a repost is made or undone. */
  onReposted: (reposted: boolean, count: number) => void;
  onQuote: () => void;
}) {
  const [open, setOpen] = useState(false);
  const [at, setAt] = useState<{ x: number; y: number } | null>(null);
  const buttonRef = useRef<HTMLButtonElement | null>(null);

  // Positioned against the button, and closed if the page moves under it.
  useEffect(() => {
    if (!open) return;

    const place = () => {
      const r = buttonRef.current?.getBoundingClientRect();
      if (!r) return;
      // Above the button. It sits low in a card, so a menu underneath it
      // falls off the bottom of the window on the last post in view.
      setAt({ x: r.left, y: r.top - 6 });
    };
    place();

    const close = () => setOpen(false);
    window.addEventListener("scroll", close, true);
    window.addEventListener("resize", place);
    return () => {
      window.removeEventListener("scroll", close, true);
      window.removeEventListener("resize", place);
    };
  }, [open]);

  async function repost() {
    setOpen(false);

    // Moved straight away; the request catches up.
    const undoing = post.reposted;
    onReposted(!undoing, post.reposts + (undoing ? -1 : 1));

    const res = await fetch(`/api/posts/${post.id}/quote`, {
      method: undoing ? "DELETE" : "POST",
      headers: { "Content-Type": "application/json" },
      body: undoing ? undefined : JSON.stringify({}),
    }).catch(() => null);

    // Put it back if the server disagreed.
    if (!res || !res.ok) onReposted(undoing, post.reposts);
  }

  /**
   * The reposting flourish.
   *
   * Every other action on this row does something when you press it — the
   * heart pops, the bookmark stamps, the share icon tilts — and repost
   * just changed colour. This is the same spin and green burst the reels
   * player already uses, so the two agree.
   */
  const [spinning, setSpinning] = useState(false);
  function flourish(el: HTMLElement | null) {
    if (post.reposted) return; // undoing is not a celebration
    if (el) firework(el, ["#2fd573", "#7dff8a", "#ffffff"]);
    sfx.repost();
    setSpinning(true);
    setTimeout(() => setSpinning(false), 650);
  }

  const items = [
    post.reposted
      ? { icon: Undo2, label: "Undo repost", action: repost, tone: "undo" }
      : {
          icon: Repeat2,
          label: "Repost",
          // The spin and the burst come off the button in the row, not the
          // menu item, because the menu is about to close.
          action: () => {
            flourish(buttonRef.current);
            repost();
          },
          tone: "",
        },
    { icon: Quote, label: "Quote", action: () => { setOpen(false); onQuote(); }, tone: "" },
  ];

  return (
    <>
      <button
        ref={buttonRef}
        onClick={(e) => {
          e.preventDefault();
          e.stopPropagation();
          setOpen((v) => !v);
        }}
        className={`pa-btn rp-btn ${post.reposted ? "on" : ""} ${spinning ? "spinning" : ""}`}
        title={post.reposted ? "Reposted" : "Repost"}
      >
        <Repeat2 size={17} />
        {post.reposts > 0 && <b className="pa-count">{post.reposts}</b>}
      </button>

      {open &&
        at &&
        typeof document !== "undefined" &&
        createPortal(
          <>
            <span className="rp-catch" onClick={() => setOpen(false)} />
            <div className="rp-menu" style={{ left: at.x, top: at.y }}>
              {items.map((item) => (
                <button
                  key={item.label}
                  onClick={item.action}
                  className={`rp-item ${item.tone}`}
                >
                  <item.icon size={16} />
                  {item.label}
                </button>
              ))}
            </div>
          </>,
          document.body
        )}
    </>
  );
}
