/* =====================================================================
   Projects v2 — admin-managed showcases.
   Reads window.MWT_SITE.projects (emitted by app/components/PublicSettingsShim.tsx).
   Each card links to project.url (https?://, validated server-side).
   Empty state: returns null so the entire #work section disappears
   when no real showcases are configured (operator policy — no
   placeholder content in production).

   Desktop: CSS auto-fit grid (unchanged).
   Mobile (<=768px): horizontal scroll-snap carousel with dot indicator,
   edge fade masks, and a one-shot "swipe to see more" hint.
   ===================================================================== */
const { useEffect: useEfPj, useMemo: useMemoPj, useRef: useRefPj, useState: useStPj } = React;

// Featured projects span 2 columns on desktop via a CSS class on the
// card root. Mobile carousel ignores the class and renders 1-up.
const FEATURED_CLASS = 'mw-projects-card mw-projects-card--featured';
const STANDARD_CLASS = 'mw-projects-card';

// Pick a deterministic background gradient for cards without a cover
// image so the visual rhythm of the section is preserved. Keyed off
// the project id so the same card always gets the same gradient
// across renders.
const SHADER_GRADIENTS = [
  'radial-gradient(circle at 50% 50%, color-mix(in oklab,var(--accent) 30%,transparent) 0%, transparent 60%), repeating-radial-gradient(circle at 50% 50%, color-mix(in oklab,var(--accent) 18%,transparent) 0px, transparent 2px, transparent 22px)',
  'conic-gradient(from 45deg at 30% 40%, color-mix(in oklab,var(--accent) 22%,transparent), transparent, color-mix(in oklab,var(--accent) 14%,transparent), transparent, color-mix(in oklab,var(--accent) 18%,transparent))',
  'repeating-linear-gradient(40deg, transparent 0px, transparent 8px, color-mix(in oklab,var(--accent) 14%,transparent) 8px, color-mix(in oklab,var(--accent) 14%,transparent) 9px), radial-gradient(ellipse at 60% 40%, color-mix(in oklab,var(--accent) 18%,transparent), transparent 70%)',
  'repeating-linear-gradient(0deg, transparent 0, transparent 12px, color-mix(in oklab,var(--accent) 12%,transparent) 12px, color-mix(in oklab,var(--accent) 12%,transparent) 13px), linear-gradient(180deg, transparent, color-mix(in oklab,var(--accent) 22%,transparent))',
  'radial-gradient(circle at 20% 30%, color-mix(in oklab,var(--accent) 26%,transparent) 0, transparent 8%), radial-gradient(circle at 70% 60%, color-mix(in oklab,var(--accent) 24%,transparent) 0, transparent 6%), radial-gradient(circle at 45% 80%, color-mix(in oklab,var(--accent) 22%,transparent) 0, transparent 7%), radial-gradient(circle at 85% 25%, color-mix(in oklab,var(--accent) 20%,transparent) 0, transparent 5%)',
  'repeating-linear-gradient(0deg, color-mix(in oklab,var(--accent) 6%,transparent) 0 1px, transparent 1px 11px), repeating-linear-gradient(90deg, color-mix(in oklab,var(--accent) 6%,transparent) 0 1px, transparent 1px 7px)',
];

function pickGradient(id) {
  if (typeof id !== 'string' || id.length === 0) return SHADER_GRADIENTS[0];
  let h = 0;
  for (let i = 0; i < id.length; i += 1) h = (h * 31 + id.charCodeAt(i)) | 0;
  return SHADER_GRADIENTS[Math.abs(h) % SHADER_GRADIENTS.length];
}

// Display label derived from a project. Prefers admin-supplied
// `domain` (canonical, no protocol); falls back to URL hostname so
// the visit-link footer always has something readable.
function displayDomain(project) {
  if (typeof project.domain === 'string' && project.domain.trim().length > 0) {
    return project.domain.trim().replace(/^https?:\/\//i, '').replace(/\/.*$/, '');
  }
  if (typeof project.url === 'string' && /^https?:\/\//i.test(project.url)) {
    try {
      return new URL(project.url).hostname.replace(/^www\./, '');
    } catch (_e) {
      return '';
    }
  }
  return '';
}

function ProjectCard({ project, index, cardRef }) {
  const [hover, setHover] = useStPj(false);
  const grad = pickGradient(project.id);
  const className = project.featured ? FEATURED_CLASS : STANDARD_CLASS;
  const domainLabel = displayDomain(project);
  const tags = Array.isArray(project.tags) ? project.tags : [];
  return (
    <a
      href={project.url}
      target="_blank"
      rel="noopener noreferrer"
      ref={cardRef}
      data-card-index={index}
      className={className}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        position: 'relative',
        display: 'flex',
        flexDirection: 'column',
        background: 'var(--bg-elev-1)',
        border: `1px solid ${hover ? 'var(--accent)' : 'var(--border)'}`,
        textDecoration: 'none',
        color: 'inherit',
        overflow: 'hidden',
        transition: 'border-color .3s, transform .3s var(--ease-out)',
        transform: hover ? 'translateY(-4px)' : 'none',
      }}
    >
      <div
        style={{
          aspectRatio: '16/10',
          background: '#0a0a0b',
          borderBottom: '1px solid var(--border)',
          position: 'relative',
          overflow: 'hidden',
        }}
      >
        {project.imageUrl ? (
          <img
            src={project.imageUrl}
            alt=""
            loading="lazy"
            decoding="async"
            referrerPolicy="no-referrer"
            style={{
              position: 'absolute',
              inset: 0,
              width: '100%',
              height: '100%',
              objectFit: 'cover',
              opacity: hover ? 1 : 0.92,
              transition: 'opacity .4s, transform .6s var(--ease-out)',
              transform: hover ? 'scale(1.03)' : 'none',
            }}
          />
        ) : (
          <div
            style={{
              position: 'absolute',
              inset: 0,
              backgroundImage: grad,
              opacity: hover ? 1 : 0.7,
              transition: 'opacity .4s',
            }}
          />
        )}
        <div
          style={{
            position: 'absolute',
            inset: 0,
            background:
              'linear-gradient(180deg,transparent 40%,color-mix(in oklab,var(--bg) 55%,transparent) 100%)',
          }}
        />
        <div
          style={{
            position: 'absolute',
            top: 12,
            left: 12,
            padding: '4px 8px',
            background: 'var(--bg)',
            color: 'var(--fg-1)',
            fontFamily: 'var(--font-mono)',
            fontSize: 10,
            letterSpacing: '0.14em',
          }}
        >
          {String(index + 1).padStart(2, '0')}
        </div>
        {project.featured ? (
          <div
            style={{
              position: 'absolute',
              top: 12,
              right: 12,
              padding: '4px 8px',
              background: 'var(--accent)',
              color: 'var(--accent-ink)',
              fontFamily: 'var(--font-mono)',
              fontSize: 10,
              letterSpacing: '0.14em',
              textTransform: 'uppercase',
            }}
          >
            Featured
          </div>
        ) : null}
        <div
          style={{
            position: 'absolute',
            bottom: 12,
            right: 12,
            fontFamily: 'var(--font-mono)',
            fontSize: 14,
            color: hover ? 'var(--accent)' : 'var(--fg-2)',
            transition: 'color .2s,transform .2s',
            transform: hover ? 'translate(2px,-2px)' : 'none',
          }}
          aria-hidden="true"
        >
          ↗
        </div>
      </div>
      <div style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 10, flex: 1 }}>
        <h3
          style={{
            margin: 0,
            fontFamily: 'var(--font-display)',
            fontSize: 22,
            fontWeight: 500,
            letterSpacing: '-0.025em',
          }}
        >
          {project.title}
        </h3>
        {project.description ? (
          <p
            style={{
              margin: 0,
              fontSize: 13,
              lineHeight: 1.55,
              color: 'var(--fg-3)',
              textWrap: 'pretty',
            }}
          >
            {project.description}
          </p>
        ) : null}
        {tags.length > 0 ? (
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {tags.map((s) => (
              <Pill key={s}>{s}</Pill>
            ))}
          </div>
        ) : null}
        <div
          style={{
            marginTop: 'auto',
            display: 'flex',
            justifyContent: 'space-between',
            alignItems: 'center',
            gap: 12,
            paddingTop: 8,
            borderTop: '1px solid var(--border)',
            fontFamily: 'var(--font-mono)',
            fontSize: 11,
            letterSpacing: '0.08em',
            color: 'var(--fg-3)',
          }}
        >
          {domainLabel ? <span>{domainLabel}</span> : <span />}
          <span style={{ color: hover ? 'var(--accent)' : 'var(--fg-2)' }}>
            Visit live site →
          </span>
        </div>
      </div>
    </a>
  );
}

function Projects() {
  const [activeIdx, setActiveIdx] = useStPj(0);
  const [hintVisible, setHintVisible] = useStPj(true);
  const ref = useRefPj(null);
  useReveal(ref);
  const scrollerRef = useRefPj(null);
  const cardRefs = useRefPj([]);

  // Read admin-managed showcases. PublicSettingsShim already sorts by
  // featured-then-order on the server side; iterate in the order
  // received. Defensive `Array.isArray` so an unexpected shape never
  // crashes the homepage stream.
  const projects = useMemoPj(() => {
    const list = (typeof window !== 'undefined' && window.MWT_SITE && window.MWT_SITE.projects) || [];
    return Array.isArray(list) ? list : [];
  }, []);

  // Reset card refs whenever the visible set changes so observers can re-attach.
  cardRefs.current = cardRefs.current.slice(0, projects.length);

  // IntersectionObserver: track which card is most centered in the carousel
  // viewport. Only meaningful on mobile, but harmless on desktop.
  useEfPj(() => {
    const root = scrollerRef.current;
    if (!root) return;
    const cards = cardRefs.current.filter(Boolean);
    if (cards.length === 0) return;
    const latestRatios = new Map();
    cards.forEach((card) => latestRatios.set(card, 0));
    const io = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          latestRatios.set(entry.target, entry.isIntersecting ? entry.intersectionRatio : 0);
        }
        let bestCard = null;
        let bestRatio = -1;
        for (const card of cards) {
          const ratio = latestRatios.get(card) || 0;
          if (ratio > bestRatio) {
            bestRatio = ratio;
            bestCard = card;
          }
        }
        if (bestCard && bestRatio > 0) {
          const idx = Number(bestCard.getAttribute('data-card-index'));
          if (!Number.isNaN(idx)) setActiveIdx(idx);
        }
      },
      { root, threshold: [0.5, 0.75, 1] },
    );
    cards.forEach((c) => io.observe(c));
    return () => io.disconnect();
  }, [projects.length]);

  // One-shot hint dismissal: once the user has scrolled the carousel any
  // measurable distance, hide the hint and stop listening.
  useEfPj(() => {
    const root = scrollerRef.current;
    if (!root || !hintVisible) return;
    const onScroll = () => {
      if (root.scrollLeft > 8) setHintVisible(false);
    };
    root.addEventListener('scroll', onScroll, { passive: true });
    return () => root.removeEventListener('scroll', onScroll);
  }, [hintVisible, projects.length]);

  // Click a dot → scroll the matching card into view.
  const goTo = (i) => {
    const card = cardRefs.current[i];
    if (!card) return;
    card.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
  };

  // Empty state: hide the entire #work section. Operator policy — no
  // placeholder showcases in production. Once at least one project is
  // configured in /admin, the section reappears on the next deploy.
  if (projects.length === 0) {
    return null;
  }

  return (
    <section
      id="work"
      ref={ref}
      className="mw-reveal"
      style={{
        padding: 'clamp(64px,10vh,100px) clamp(20px,4vw,32px) 40px',
        maxWidth: 1440,
        margin: '0 auto',
      }}
    >
      <SectionHead
        eyebrow="002 / Selected work"
        title={
          <>
            Selected projects,
            <br />
            <em
              style={{
                fontFamily: 'var(--font-editorial)',
                fontStyle: 'italic',
                fontWeight: 400,
              }}
            >
              real client websites.
            </em>
          </>
        }
        kicker="Live sites we built and ship for. Click any card to visit the project."
      />
      <div className="mw-projects-wrap">
        <div ref={scrollerRef} className="mw-projects-grid">
          {projects.map((p, i) => (
            <ProjectCard
              key={p.id}
              project={p}
              index={i}
              cardRef={(el) => {
                cardRefs.current[i] = el;
              }}
            />
          ))}
        </div>
        {/* Edge fade masks — purely decorative; CSS hides on desktop. */}
        <div className="mw-projects-fade mw-projects-fade-l" aria-hidden="true" />
        <div className="mw-projects-fade mw-projects-fade-r" aria-hidden="true" />
      </div>
      {/* Dots + hint — visible only on mobile via CSS. The dots advertise
          carousel position only; they are not a tabs widget (no associated
          tabpanels), so we use plain buttons with aria-current rather than
          the role="tablist"/role="tab" pattern. */}
      <div className="mw-projects-dots" role="group" aria-label="Projects carousel position">
        {projects.map((p, i) => (
          <button
            key={p.id}
            type="button"
            aria-label={`Go to project ${i + 1} of ${projects.length}`}
            aria-current={i === activeIdx ? 'true' : undefined}
            onClick={() => goTo(i)}
            className={`mw-projects-dot${i === activeIdx ? ' is-active' : ''}`}
          />
        ))}
      </div>
      {hintVisible && projects.length > 1 ? (
        <div className="mw-projects-hint" aria-hidden="true">
          Swipe to see more →
        </div>
      ) : null}
    </section>
  );
}

Object.assign(window, { Projects });
