// carousel.jsx — Carousel composition for the social-post builder.
//
// Slide 1 = the currently selected template (with its data + photo).
// Slides 2-N = SecondarySlide instances with their own image-slot drop
// zones, styled minimally so the photo dominates.
//
// Swipeable via pointer drag (and arrows + dots are rendered by the parent
// since they're chrome, not part of the design).
//
// Each slide is wrapped in a data-carousel-slide="N" div so the export
// pipeline can `querySelector` it and capture each slide independently.

const { useRef: useCarouselRef, useEffect: useCarouselEffect } = React;

// ──────────────────────────────────────────────────────────────────────────
// SecondarySlide — minimalist slide for positions 2..N.
//
// Overlays (each independent, can stack):
//   styles.watermark → small 16°S monogram top-left
//   styles.meta      → "// CLIENT · LOCATION" eyebrow top-right
//   styles.caption   → bottom strip with location + NN / NN slide counter
//
// If no overlays are enabled the slide is a pure full-bleed photo.
// ──────────────────────────────────────────────────────────────────────────
function SecondarySlide({ w, h, slotId, styles = {}, index, total, location, client }) {
  const u = Math.min(w, h) / 100;
  const inkOnPhoto = '#F2EFEA';
  const accentOnPhoto = '#61D4F2';
  const hasTopScrim = styles.watermark || styles.meta;
  const hasBottomScrim = styles.caption;

  return (
    <div
      data-secondary-slide="1"
      style={{
        position: 'relative',
        width: w,
        height: h,
        background: 'var(--navy-deep)',
        overflow: 'hidden',
      }}
    >
      <image-slot
        id={slotId}
        shape="rect"
        placeholder={`Slide ${index + 1} · drop a photo`}
        style={{
          position: 'absolute',
          inset: 0,
          width: '100%',
          height: '100%',
          background: 'linear-gradient(135deg, #02102B 0%, #0F6D96 60%, #001172 100%)',
          '--is-bg': 'transparent',
        }}
      ></image-slot>

      {/* Scrims for legibility — only rendered if overlays are present. */}
      {hasTopScrim && (
        <div
          style={{
            position: 'absolute', inset: 0,
            background: 'linear-gradient(180deg, rgba(2,16,43,0.5) 0%, rgba(2,16,43,0) 18%)',
            pointerEvents: 'none',
          }}
        />
      )}
      {hasBottomScrim && (
        <div
          style={{
            position: 'absolute', inset: 0,
            background: 'linear-gradient(180deg, rgba(2,16,43,0) 65%, rgba(2,16,43,0.85) 100%)',
            pointerEvents: 'none',
          }}
        />
      )}

      {/* Top-left: watermark */}
      {styles.watermark && (
        <div
          style={{
            position: 'absolute',
            top: u * 4,
            left: u * 4,
            fontFamily: 'var(--font-display)',
            color: inkOnPhoto,
            fontSize: u * 3.5,
            letterSpacing: '-0.02em',
            lineHeight: 1.15,
            paddingBottom: u * 0.4,
            textShadow: '0 1px 4px rgba(0,0,0,0.5)',
          }}
        >16°S</div>
      )}

      {/* Top-right: client · location */}
      {styles.meta && (
        <div
          style={{
            position: 'absolute',
            top: u * 4,
            right: u * 4,
            fontFamily: 'var(--font-brand)',
            color: inkOnPhoto,
            fontSize: u * 1.9,
            fontWeight: 600,
            letterSpacing: '0.18em',
            textTransform: 'uppercase',
            textAlign: 'right',
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'flex-end',
            gap: u * 0.4,
            textShadow: '0 1px 4px rgba(0,0,0,0.5)',
          }}
        >
          {client ? <span><span style={{ color: accentOnPhoto }}>// </span>{client}</span> : null}
          {location ? <span style={{ color: 'rgba(242,239,234,0.85)' }}>{location}</span> : null}
        </div>
      )}

      {/* Bottom: caption (location + NN / NN) */}
      {styles.caption && (
        <div
          style={{
            position: 'absolute',
            bottom: u * 4,
            left: u * 4,
            right: u * 4,
            display: 'flex',
            justifyContent: 'space-between',
            alignItems: 'flex-end',
            gap: u * 2,
            color: inkOnPhoto,
            fontFamily: 'var(--font-brand)',
            fontSize: u * 1.9,
            fontWeight: 600,
            letterSpacing: '0.18em',
            textTransform: 'uppercase',
          }}
        >
          <span><span style={{ color: accentOnPhoto }}>// </span>{location || '\u2014'}</span>
          <span style={{ color: accentOnPhoto, fontVariantNumeric: 'tabular-nums' }}>
            {String(index + 1).padStart(2, '0')} / {String(total).padStart(2, '0')}
          </span>
        </div>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Carousel — composes slide 1 (the supplied React node, usually the chosen
// template) with N-1 SecondarySlides, swipeable via pointer drag. The host
// (builder) owns currentIndex/onIndexChange state — that lets it drive
// programmatic navigation (export loop) and reuse arrow/dot chrome.
// ──────────────────────────────────────────────────────────────────────────
function Carousel({
  w, h,
  slideCount,
  currentIndex,
  onIndexChange,
  firstSlide,
  secondaryStyles = { caption: true },
  location,
  client,
  carouselId = 'default',
}) {
  const containerRef = useCarouselRef(null);
  const dragState = useCarouselRef({ active: false, startX: 0, startIndex: 0 });

  const onPointerDown = (e) => {
    if (e.button != null && e.button !== 0) return;
    // Don't capture pointer if user clicked on a drop zone, button, or input.
    if (e.target.closest('image-slot, video, button, input, textarea, [data-no-export]')) return;
    dragState.current = {
      active: true,
      startX: e.clientX,
      startIndex: currentIndex,
    };
  };

  useCarouselEffect(() => {
    const onUp = (e) => {
      if (!dragState.current.active) return;
      const deltaX = e.clientX - dragState.current.startX;
      const threshold = Math.max(40, w * 0.12);
      let newIndex = dragState.current.startIndex;
      if (deltaX < -threshold && newIndex < slideCount - 1) newIndex++;
      else if (deltaX > threshold && newIndex > 0) newIndex--;
      onIndexChange(newIndex);
      dragState.current.active = false;
    };
    window.addEventListener('pointerup', onUp);
    window.addEventListener('pointercancel', onUp);
    return () => {
      window.removeEventListener('pointerup', onUp);
      window.removeEventListener('pointercancel', onUp);
    };
  }, [w, slideCount, onIndexChange]);

  const slides = [];
  // Slide 0 — the supplied React node (existing template).
  slides.push(
    <div
      key={0}
      data-carousel-slide="0"
      style={{ width: w, height: h, flex: '0 0 auto' }}
    >{firstSlide}</div>
  );
  // Slides 1..N-1 — SecondarySlides.
  for (let i = 1; i < slideCount; i++) {
    slides.push(
      <div
        key={i}
        data-carousel-slide={String(i)}
        style={{ width: w, height: h, flex: '0 0 auto' }}
      >
        <SecondarySlide
          w={w} h={h}
          slotId={`carousel-${carouselId}-${i}`}
          styles={secondaryStyles}
          index={i}
          total={slideCount}
          location={location}
          client={client}
        />
      </div>
    );
  }

  return (
    <div
      ref={containerRef}
      onPointerDown={onPointerDown}
      style={{
        position: 'relative',
        width: w,
        height: h,
        overflow: 'hidden',
        cursor: 'grab',
        userSelect: 'none',
      }}
    >
      <div
        style={{
          display: 'flex',
          width: '100%',
          height: '100%',
          transform: `translateX(-${currentIndex * w}px)`,
          transition: 'transform 0.35s cubic-bezier(0.16, 1, 0.3, 1)',
        }}
      >{slides}</div>
    </div>
  );
}

window.Carousel = Carousel;
window.SecondarySlide = SecondarySlide;
