/*
 * AccordionGallery — ported from React Bits for browser Babel runtime.
 *
 * Differences from the original ESM source:
 *   - No `import` statements. Uses React from the global (`React.useRef`, etc.)
 *     and GSAP from `window.gsap` (both loaded via CDN <script> in the host HTML).
 *   - Exposed on window as `window.AccordionGallery` for other Babel scripts.
 *   - CSS lives in AccordionGallery.css, loaded via <link> in the host HTML.
 */
(() => {
  const { useRef, useEffect, useState, useCallback } = React;

  const DEFAULT_ITEMS = [
    { image: 'assets/accordion/01-hybrid.jpg', label: 'Hybrid model', link: '#' },
    { image: 'assets/accordion/02-global.jpg', label: 'Global reach', link: '#' },
    { image: 'assets/accordion/03-ds-international.jpg', label: 'Global trade focus', link: '#' },
    { image: 'assets/accordion/04-execution.jpg', label: 'Execution discipline', link: '#' },
  ];

  const AccordionGallery = ({
    items = DEFAULT_ITEMS,
    defaultIndex = 2,
    accentColor = '#ffffff',
    overlayColor = '#060010',
    textColor = '#ffffff',
    height = 460,
    gap = 10,
    radius = 16,
    expandRatio = 0.52,
    orientation = 'horizontal',
    duration = 0.6,
    ease = 'power3.out',
    parallax = 0.5,
    tilt = 8,
    stagger = 0.06,
    trigger = 'hover',
    showLabels = true,
    grayscale = true,
    className = ''
  }) => {
    const rootRef = useRef(null);
    const panelRefs = useRef([]);
    const mediaRefs = useRef([]);
    const barRefs = useRef([]);
    const textRefs = useRef([]);
    const tlRef = useRef(null);
    const firstRunRef = useRef(true);
    const mediaSizeRef = useRef(320);

    const vertical = orientation === 'vertical';
    const count = items.length;
    const [active, setActive] = useState(Math.min(Math.max(defaultIndex, 0), count - 1));

    const prefersReduced =
      typeof window !== 'undefined' && window.matchMedia
        ? window.matchMedia('(prefers-reduced-motion: reduce)').matches
        : false;

    const applyLayout = useCallback(
      (animate) => {
        const gsap = window.gsap;
        if (!gsap) return;
        const panels = panelRefs.current;
        if (!panels.length) return;

        const r = Math.min(Math.max(expandRatio, 0.2), 0.9);
        const grow = count > 1 ? (r * (count - 1)) / (1 - r) : 1;
        const mediaSize = mediaSizeRef.current;

        tlRef.current && tlRef.current.kill();
        const dur = animate && !prefersReduced ? duration : 0;
        const tl = gsap.timeline();

        panels.forEach((panel, i) => {
          if (!panel) return;
          const isActive = i === active;
          const media = mediaRefs.current[i];
          const bar = barRefs.current[i];
          const text = textRefs.current[i];

          const rot = isActive ? 0 : i < active ? tilt : -tilt;
          const rotProp = vertical ? { rotateX: -rot } : { rotateY: rot };

          // force3D lifts the panel onto a compositor layer during the
          // flex-grow interpolation → no subpixel jitter at the trailing
          // edge. Turning it off when the tween finishes lets the browser
          // hand the layer back so it doesn't hoard GPU memory.
          tl.to(panel, { flexGrow: isActive ? grow : 1, ...rotProp, duration: dur, ease, force3D: true }, 0);

          if (media) {
            const drift = Math.max(-1.5, Math.min(1.5, active - i));
            const shift = drift * parallax * mediaSize * 0.06;
            // Grayscale + dim veil are handled purely by the
            // .ag-panel--active CSS class swap on the panel element
            // (see AccordionGallery.css). GSAP interpolating CSS
            // custom properties without an @property registration
            // was unreliable, so class-based transitions win.
            tl.to(
              media,
              {
                xPercent: -50,
                yPercent: -50,
                x: vertical ? 0 : isActive ? 0 : shift,
                y: vertical ? (isActive ? 0 : shift) : 0,
                duration: dur,
                ease,
              },
              0
            );
          }

          // Labels are always visible on desktop. We keep GSAP touching
          // them so any inline transform/opacity artifacts get zeroed out.
          if (showLabels && bar && text) {
            tl.to(
              [bar, text],
              { opacity: 1, x: 0, duration: dur, ease },
              0
            );
          }
        });

        tlRef.current = tl;
      },
      [active, count, expandRatio, duration, ease, vertical, tilt, parallax, grayscale, showLabels, stagger, prefersReduced]
    );

    useEffect(() => {
      const el = rootRef.current;
      if (!el) return;

      const measure = () => {
        const rect = el.getBoundingClientRect();
        const total = vertical ? rect.height : rect.width;
        const usable = Math.max(total - gap * (count - 1), 120);
        const size = Math.max(140, usable * Math.min(Math.max(expandRatio, 0.2), 0.9) * 1.22);
        mediaSizeRef.current = size;
        el.style.setProperty('--ag-media-size', `${size}px`);
        applyLayout(!firstRunRef.current);
      };

      measure();
      const ro = new ResizeObserver(measure);
      ro.observe(el);
      return () => ro.disconnect();
    }, [applyLayout, gap, count, expandRatio, vertical]);

    useEffect(() => {
      applyLayout(!firstRunRef.current);
      firstRunRef.current = false;
    }, [applyLayout]);

    useEffect(
      () => () => {
        tlRef.current && tlRef.current.kill();
      },
      []
    );

    const handleEnter = (i) => {
      if (trigger === 'hover') setActive(i);
    };
    const handleClick = (i, e) => {
      if (i !== active) {
        e.preventDefault();
        setActive(i);
      }
    };
    const handleKeyDown = (i, e) => {
      if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
        e.preventDefault();
        setActive((i + 1) % count);
      } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
        e.preventDefault();
        setActive((i - 1 + count) % count);
      }
    };

    return (
      <div
        ref={rootRef}
        className={`accordion-gallery${vertical ? ' accordion-gallery--vertical' : ''}${className ? ` ${className}` : ''}`}
        style={{
          '--ag-accent': accentColor,
          '--ag-overlay': overlayColor,
          '--ag-text': textColor,
          '--ag-gap': `${gap}px`,
          '--ag-radius': `${radius}px`,
          height: vertical ? `${Math.round(height * 1.6)}px` : `${height}px`,
        }}
        role="list"
        aria-label="Image accordion gallery"
      >
        {items.map((item, i) => {
          const isActive = i === active;
          const Tag = item.link ? 'a' : 'div';
          return (
            <Tag
              key={i}
              ref={(el) => (panelRefs.current[i] = el)}
              className={`ag-panel${isActive ? ' ag-panel--active' : ''}`}
              style={{ borderRadius: `${radius}px` }}
              href={item.link || undefined}
              onClick={(e) => handleClick(i, e)}
              onMouseEnter={() => handleEnter(i)}
              onFocus={() => setActive(i)}
              onKeyDown={(e) => handleKeyDown(i, e)}
              role="listitem"
              tabIndex={0}
              aria-current={isActive ? 'true' : undefined}
              aria-label={item.label}
            >
              <span className="ag-panel__frame">
                <span className="ag-panel__media" ref={(el) => (mediaRefs.current[i] = el)}>
                  <img src={item.image} alt={item.alt || item.label || ''} draggable="false" />
                </span>
                <span className="ag-panel__overlay" aria-hidden="true" />
              </span>
              {showLabels && (
                <span className="ag-panel__label" aria-hidden="true">
                  <span className="ag-panel__bar" ref={(el) => (barRefs.current[i] = el)} />
                  {/* Editorial link vocabulary: the brand name itself
                      IS the link affordance. No pill, no separate CTA.
                      Hover paints a hairline underline under the label
                      and nudges the arrow to the right. Panel is
                      already <a>, so this is pure visual signal. */}
                  <span className={`ag-panel__text ${item.link ? 'ag-panel__text--link' : ''}`} ref={(el) => (textRefs.current[i] = el)}>
                    <span className="ag-panel__name">{item.label}</span>
                    {item.link && (
                      <svg className="ag-panel__arrow" viewBox="0 0 24 12" aria-hidden="true">
                        <line x1="0" y1="6" x2="22" y2="6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
                        <polyline points="16 1 22 6 16 11" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
                      </svg>
                    )}
                  </span>
                </span>
              )}
            </Tag>
          );
        })}
      </div>
    );
  };

  window.AccordionGallery = AccordionGallery;
})();
