/* archive-hover.jsx — Archive / Works as a hover-driven studio list.
 *
 * Vertical list of projects (small type, light-grey by default). Hovering a
 * row promotes it to active (ink) and opens a masked preview slot directly
 * UNDER that row. The lead image slides DOWN into the slot through the
 * mask while the previously active row's slot closes in the same tick —
 * its image sliding UP and out through the mask.
 *
 * Animation contract (mirrored in CSS):
 *   • duration 0.7s
 *   • easing   cubic-bezier(0.22, 1, 0.36, 1)
 *   • motion   Y-axis only — slot grid-row 0fr → 1fr,
 *              image translateY -101% → 0. No fade, no bounce, no elastic.
 *
 * Reflow note: the closing and opening slots animate in lockstep, so the
 * net height change across the list during a swap is zero — rows outside
 * the moving pair stay put, and rows between them shift by 0 net pixels.
 */

const { useState: useStateArc, useCallback: useCbArc } = React;
const { MediaSlot: MSlotArc } = window;
const edArc = window.ed;

function ArchiveHover({ lang, onOpen }) {
  const { COPY, PROJECTS } = window.PORTFOLIO;
  const U = COPY.ui;

  // No default active row — the preview is closed until the cursor enters
  // the list. Leaving the list closes it again.
  const [active, setActive] = useStateArc(null);

  const promote = useCbArc((i) => { if (i !== active) setActive(i); }, [active]);
  const dismiss = useCbArc(() => setActive(null), []);

  const onRowKey = (i) => (e) => {
    if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onOpen && onOpen(i); return; }
    if (e.key === 'ArrowDown') {
      e.preventDefault();
      const n = (i + 1) % PROJECTS.length;
      promote(n);
      document.getElementById(`arc-row-${n}`)?.focus();
    }
    if (e.key === 'ArrowUp') {
      e.preventDefault();
      const n = (i - 1 + PROJECTS.length) % PROJECTS.length;
      promote(n);
      document.getElementById(`arc-row-${n}`)?.focus();
    }
  };

  return (
    <section className="arc">
      <ol className="arc-list" role="list" onMouseLeave={dismiss}>
        {PROJECTS.map((p, i) => {
          const isActive = active === i;
          return (
            <li key={p.id} className="arc-item">
              <button
                id={`arc-row-${i}`}
                type="button"
                className={`arc-row ${isActive ? 'is-active' : ''}`}
                onMouseEnter={() => promote(i)}
                onFocus={() => promote(i)}
                onClick={() => onOpen && onOpen(i)}
                onKeyDown={onRowKey(i)}
              >
                <span className="arc-title" {...edArc(`proj-${p.id}-client`)}>
                  {p.client[lang]}
                </span>
                <span className="arc-meta">
                  <span className="arc-meta-cat" {...edArc(`proj-${p.id}-type2`)}>
                    {p.typeLabel[lang]}
                  </span>
                  <span className="arc-meta-year" {...edArc(`proj-${p.id}-year`)}>{p.year}</span>
                </span>
              </button>

              {/* Slot lives in the row's flow so the preview opens UNDER its
                  title. grid-template-rows 0fr → 1fr does the height animate;
                  the image inside translates -101% → 0 over the same tick. */}
              <div className={`arc-slot ${isActive ? 'is-open' : ''}`} aria-hidden={!isActive}>
                <div className="arc-slot-inner">
                  <div className="arc-slot-img" style={{ '--tone': p.tone }}>
                    <MSlotArc
                      id={`proj-${p.id}-lead`}
                      lang={lang}
                      tone={p.tone}
                      fit="cover"
                      label={`P/${p.idx}`}
                    />
                  </div>
                </div>
              </div>
            </li>
          );
        })}
      </ol>
    </section>
  );
}

window.ArchiveHover = ArchiveHover;
