/* gnb.jsx — Shared navigation + button components
   Loaded before every page JSX file.
   Exports: Btn, VerticalGuides, HeroGNB (dark/index), StudioGNB (light/studio+privacy)
*/

// ─────────────────────────────────────────
// SHARED HOOKS
// ─────────────────────────────────────────

function useToast(duration = 2000) {
  const [vis, setVis] = React.useState(false);
  const timer = React.useRef(null);
  function show() {
    setVis(true);
    clearTimeout(timer.current);
    timer.current = setTimeout(() => setVis(false), duration);
  }
  return [vis, show];
}

// ─────────────────────────────────────────
// SHARED ACTION HELPERS
// ─────────────────────────────────────────

function pinImage(imgSrc, pageUrl, description) {
  const abs = src => new URL(src, window.location.href).href;
  if (typeof PinUtils !== 'undefined') {
    PinUtils.pinOne({ media: abs(imgSrc), url: pageUrl, description: description || '' });
  } else {
    const url = 'https://pinterest.com/pin/create/button/?url=' + encodeURIComponent(pageUrl)
      + '&media=' + encodeURIComponent(abs(imgSrc))
      + '&description=' + encodeURIComponent(description || '');
    window.open(url, '_blank', 'width=750,height=550,noopener,noreferrer');
  }
}

function copyUrl(url, onSuccess) {
  if (navigator.clipboard) {
    navigator.clipboard.writeText(url).then(onSuccess).catch(() => {});
  } else {
    try {
      const ta = document.createElement('textarea');
      ta.value = url; ta.style.position = 'fixed'; ta.style.opacity = '0';
      document.body.appendChild(ta); ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
      onSuccess();
    } catch (e) {}
  }
}

function useHlsVideo(ref, src, fallback) {
  React.useEffect(() => {
    if (!ref.current || !src) return;
    const video = ref.current;
    if (typeof window.Hls !== 'undefined' && window.Hls.isSupported()) {
      const hls = new window.Hls();
      hls.loadSource(src);
      hls.attachMedia(video);
      hls.on(window.Hls.Events.MANIFEST_PARSED, () => video.play().catch(() => {}));
      hls.on(window.Hls.Events.ERROR, (_, d) => {
        if (d.fatal && fallback) { hls.destroy(); video.src = fallback; }
      });
      return () => hls.destroy();
    }
    if (video.canPlayType('application/vnd.apple.mpegurl')) {
      video.src = src;
    } else if (fallback) {
      video.src = fallback;
    }
  }, [src]);
}

// ─────────────────────────────────────────
// PAGE TRANSITION HELPER
// ─────────────────────────────────────────

// Programmatic navigation — lets @view-transition catch it in supported browsers,
// falls back to CSS class-based fade for others.
function navigateTo(url) {
  if (document.startViewTransition) {
    window.location.href = url;
    return;
  }
  const curtain = document.createElement('div');
  curtain.className = 'vt-curtain';
  document.body.appendChild(curtain);
  requestAnimationFrame(() => requestAnimationFrame(() => {
    curtain.classList.add('vt-curtain--up');
  }));
  setTimeout(() => { window.location.href = url; }, 700);
}

// ─────────────────────────────────────────
// CONSTANTS
// ─────────────────────────────────────────

const NAV_LINKS = [
  { label: 'WORK',    href: 'work.html' },
  { label: 'FEED',    href: 'feed.html' },
  { label: 'STUDIO',  href: 'studio.html' },
  { label: 'CONTACT', href: 'contact.html' },
];

const GUIDES = [
  { to: '4vw',  dur: 2400, delay:   0 },
  { to: '24vw', dur: 2600, delay: 100 },
  { to: '62vw', dur: 2800, delay: 200 },
  { to: '76vw', dur: 2600, delay: 300 },
  { to: '97vw', dur: 2400, delay: 400 },
];

// ─────────────────────────────────────────
// COMPONENTS
// ─────────────────────────────────────────

// Shared button: ( LABEL ) — hover underlines .btn-label only
// Usage: <Btn className="..." onClick={...}>LABEL TEXT</Btn>
function Btn({ className, onClick, children }) {
  return (
    <button className={className} onClick={onClick}>
      ( <span className="btn-label">{children}</span> )
    </button>
  );
}

// Shared form row: label | input | ( btn )
// Uncontrolled by default (studio contact). Pass value+onChange+onSubmit for controlled mode (work search).
function FormRow({ label, placeholder, type = 'text', btnLabel = '→', className, value, onChange, onSubmit }) {
  function handleKey(e) {
    if (e.key === 'Enter' && onSubmit) onSubmit();
  }
  return (
    <div className={`form-row${className ? ' ' + className : ''}`}>
      <span className="form-row__label">{label}</span>
      <input
        className="form-row__input"
        type={type}
        placeholder={placeholder}
        aria-label={label}
        value={value}
        onChange={onChange}
        onKeyDown={handleKey}
      />
      <Btn className="form-row__btn" onClick={onSubmit}>{btnLabel}</Btn>
    </div>
  );
}

function VerticalGuides({ fixed = false }) {
  return (
    <div
      className={fixed ? 'guides s-guides-fixed' : 'guides'}
      aria-hidden="true"
    >
      {GUIDES.map((g, i) => (
        <div
          key={i}
          className={fixed ? 'guide-line s-guide-line' : 'guide-line'}
          style={{ '--to': g.to, '--dur': `${g.dur}ms`, '--delay': `${g.delay}ms` }}
        />
      ))}
    </div>
  );
}

// ─────────────────────────────────────────
// AGENT OVERLAY
// ─────────────────────────────────────────

// Static page registry — in production, type/desc/thumb would be fetched
// from each page's OG meta tags (<meta property="og:image"> etc.)
const PAGE_META = {
  'work.html':        { type: 'WORK',    desc: 'Selected brand projects across identity, packaging, and visual systems.', thumb: 'assets/sample-image-landscape.jpg' },
  'studio.html':      { type: 'STUDIO',  desc: 'A branding creative studio built on Ethos, Craft, and Staying Power.',     thumb: 'assets/sample-image-wide.jpg'      },
  'feed.html':        { type: 'FEED',    desc: 'Perspectives on brand strategy, visual culture, and the creative process.', thumb: 'assets/sample-image-portrait.jpg'  },
  'contact.html':     { type: 'CONTACT', desc: 'Begin your inquiry. Every project starts with a conversation.',             thumb: null                                },
  'work-detail.html': { type: 'WORK',    date: '04/04/25', desc: 'DIRE — Brand redesign & modernization for Korea Fund Partners.', thumb: 'assets/sample-image-square.jpg' },
};

const MOCK_RESPONSES = [
  {
    keywords: ['work', 'portfolio', 'project', 'case', 'client'],
    answer: "Our work spans corporate identity, retail, hospitality, and finance. Each project is shaped by the brand's actual ethos — not category convention.",
    sources: [{ href: 'work.html' }, { href: 'work-detail.html' }],
  },
  {
    keywords: ['brand', 'branding', 'identity', 'logo', 'visual'],
    answer: "HYPT builds brand systems designed for Staying Power — visual identity, verbal language, and every artifact that carries it forward.",
    sources: [{ href: 'work.html' }, { href: 'studio.html' }, { href: 'work-detail.html' }],
  },
  {
    keywords: ['studio', 'about', 'team', 'who', 'hypt'],
    answer: "HYPT is a branding creative studio with offices in Seoul and Yangjae. We believe in three principles: Ethos, Craft, and Staying Power.",
    sources: [{ href: 'studio.html' }],
  },
  {
    keywords: ['feed', 'blog', 'article', 'news', 'read'],
    answer: "The Feed is where we share perspectives on brand strategy, visual culture, and the work behind the work.",
    sources: [{ href: 'feed.html' }],
  },
  {
    keywords: ['contact', 'inquiry', 'email', 'quote', 'start', 'begin', 'hire', 'price', 'cost', 'budget'],
    answer: "Every project begins with a conversation. Tell us what you're building and we'll take it from there.",
    sources: [{ href: 'contact.html' }],
  },
  {
    keywords: ['packaging', 'print', 'product'],
    answer: "From brand guidelines to packaging systems and print artifacts — we design the physical layer of your brand world.",
    sources: [{ href: 'work.html' }, { href: 'work-detail.html' }],
  },
  {
    keywords: ['seoul', 'korea', 'office', 'location', 'address'],
    answer: "HYPT is based in Seoul, South Korea, with studios in the city center and Yangjae.",
    sources: [{ href: 'studio.html' }],
  },
];

const AGENT_FALLBACK = {
  answer: "Let's talk. The best way to explore what HYPT can do for your brand is to start a conversation.",
  sources: [{ href: 'contact.html' }],
};

function AgentOverlay({ activePage, onClose }) {
  const [query, setQuery] = React.useState('');
  const [submitted, setSubmitted] = React.useState(null);
  const [response, setResponse] = React.useState(null);
  const [thinking, setThinking] = React.useState(false);
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (inputRef.current) inputRef.current.focus();
    function onKey(e) { if (e.key === 'Escape') onClose(); }
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [onClose]);

  function handleChange(e) {
    setQuery(e.target.value);
    if (submitted !== null) { setSubmitted(null); setResponse(null); }
  }

  function handleSubmit() {
    const q = query.trim().toLowerCase();
    if (!q) return;
    const navMatch = NAV_LINKS.find(l => l.label.toLowerCase() === q);
    if (navMatch) { navigateTo(navMatch.href); return; }
    setSubmitted(query.trim());
    setThinking(true);
    setResponse(null);
    setTimeout(() => {
      const found = MOCK_RESPONSES.find(r => r.keywords.some(k => q.includes(k)));
      setResponse(found || AGENT_FALLBACK);
      setThinking(false);
    }, 2000);
  }

  return ReactDOM.createPortal(
    <div className="ag-panel">
      <div className="ag-body">

        <div className="ag-header">
          <span className="ag-title">HYPT AGENT</span>
          <Btn className="ag-close-btn" onClick={onClose}>X</Btn>
        </div>

        <div className="ag-input-wrap">
          <input
            ref={inputRef}
            className="ag-input"
            type="text"
            value={query}
            onChange={handleChange}
            onKeyDown={e => { if (e.key === 'Enter') handleSubmit(); }}
            placeholder="ASK ME ABOUT OUR STUDIO"
          />
          <Btn className="ag-submit-btn" onClick={handleSubmit}>↓</Btn>
        </div>

        {submitted && (
          <div className="ag-result">
            {thinking ? (
              <p className="ag-thinking">( THINKING... )</p>
            ) : response && (
              <>
                <div className="ag-section">
                  <span className="ag-section-label">AGENT'S ANSWER_</span>
                  <p className="ag-answer">{response.answer}</p>
                </div>
                <div className="ag-section">
                  <span className="ag-section-label">GROUNDED SOURCES_</span>
                  {response.sources.map((s, i) => {
                    const m = PAGE_META[s.href] || {};
                    const type  = m.type  || 'PAGE';
                    const date  = m.date  || '';
                    const desc  = m.desc  || '';
                    const thumb = m.thumb || null;
                    return (
                      <a key={i} href={s.href} className="ag-source">
                        <div className="ag-source__left">
                          <span className="ag-source__meta">{type}{date ? ` · ${date}` : ''}</span>
                          {desc && <p className="ag-source__desc">{desc}</p>}
                        </div>
                        {thumb && <img src={thumb} className="ag-source__thumb" alt="" />}
                      </a>
                    );
                  })}
                </div>
              </>
            )}
          </div>
        )}

      </div>
    </div>,
    document.body
  );
}

// Shared menu toggle: MENU +/X dropdown + AgentOverlay
// wrapClass: positioning wrapper class per GNB variant
// btnClass: button class per GNB variant
// onAgentChange: optional callback so parent can react to panel open/close
function GnbMenu({ activePage, wrapClass, btnClass, onAgentChange }) {
  const [menuOpen,  setMenuOpen]  = React.useState(false);
  const [agentOpen, setAgentOpen] = React.useState(false);

  React.useEffect(() => {
    document.body.classList.toggle('agent-open', agentOpen);
    onAgentChange?.(agentOpen);
    return () => document.body.classList.remove('agent-open');
  }, [agentOpen]);

  return (
    <div className={wrapClass}>
      <Btn className={btnClass} onClick={e => { e.stopPropagation(); setMenuOpen(o => !o); }}>
        MENU {menuOpen ? '×' : '+'}
      </Btn>
      {menuOpen && (
        <div className="s-dropdown">
          {NAV_LINKS.map(({ label, href }) => (
            <a key={label} href={href}
               className={`s-dropdown__item${activePage === label ? ' s-dropdown__item--active' : ''}`}>
              {label}
            </a>
          ))}
          <span className="s-dropdown__sep">·</span>
          <button className="s-dropdown__item s-dropdown__item--agent"
            onClick={e => { e.stopPropagation(); setAgentOpen(true); }}>
            HYPT AGENT
          </button>
        </div>
      )}
      {agentOpen && <AgentOverlay activePage={activePage} onClose={() => setAgentOpen(false)} />}
    </div>
  );
}

// Dark variant — index.html (hero bg)
function HeroGNB({ activePage, onLogoClick }) {
  return (
    <div className="hero__gnb">
      <img src={DATA.logo} alt="HYPT" className="hero__logo" onClick={onLogoClick} />
      <GnbMenu activePage={activePage} wrapClass="hero__menu-wrap" btnClass="hero__menu-btn" />
    </div>
  );
}

// Shared site footer — used on all white-bg pages
function SiteFooter() {
  return (
    <footer className="s-footer">
      <span>© 2026 HYPT</span>
      <div className="s-footer__right">
        <a href="privacy.html" className="s-footer__link">PRIVACY</a>
        <span className="s-footer__sep">·</span>
        <a href="https://www.behance.net/hypt" target="_blank" rel="noopener noreferrer" className="s-footer__link">BEHANCE</a>
        <span className="s-footer__sep">·</span>
        <a href="https://www.instagram.com/hypt.design/" target="_blank" rel="noopener noreferrer" className="s-footer__link">INSTAGRAM</a>
      </div>
    </footer>
  );
}

// ─────────────────────────────────────────
// LIGHTBOX
// ─────────────────────────────────────────

// slides: string[]  initialIdx: number  onClose: fn
// Single image if slides.length === 1; slideshow + thumb strip if > 1
function Lightbox({ slides, initialIdx = 0, onClose }) {
  const [idx, setIdx] = React.useState(initialIdx);
  const multi = slides.length > 1;

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = ''; };
  }, []);

  React.useEffect(() => {
    function onKey(e) {
      if (e.key === 'Escape') onClose();
      if (multi && e.key === 'ArrowLeft')  setIdx(i => (i - 1 + slides.length) % slides.length);
      if (multi && e.key === 'ArrowRight') setIdx(i => (i + 1) % slides.length);
    }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [multi, slides.length, onClose]);

  function prev() { setIdx(i => (i - 1 + slides.length) % slides.length); }
  function next() { setIdx(i => (i + 1) % slides.length); }

  return ReactDOM.createPortal(
    <div className="lb" onClick={onClose}>
      {/* Close */}
      <button className="lb__close" onClick={onClose}>
        ( <span className="btn-label">X</span> )
      </button>

      {/* Stage */}
      <div className="lb__stage" onClick={e => e.stopPropagation()}>
        <img src={slides[idx]} className="lb__img" alt="" />
      </div>

      {/* Thumbnail nav strip — multi only */}
      {multi && (
        <div className="lb__nav" onClick={e => e.stopPropagation()}>
          <button className="lb__nav-arrow" onClick={prev}>
            ( <span className="btn-label">←</span> )
          </button>
          <div className="lb__thumbs">
            {slides.map((src, i) => (
              <button
                key={i}
                className={`lb__thumb${i === idx ? ' lb__thumb--active' : ''}`}
                onClick={() => setIdx(i)}
              >
                <img src={src} alt="" />
              </button>
            ))}
          </div>
          <button className="lb__nav-arrow" onClick={next}>
            ( <span className="btn-label">→</span> )
          </button>
        </div>
      )}
    </div>,
    document.body
  );
}

// Light variant — studio.html, privacy.html (white bg)
// leftSlot: optional node rendered on the left, mirroring the MENU button
function StudioGNB({ activePage, leftSlot }) {
  const [agentOpen, setAgentOpen] = React.useState(false);
  return (
    <header className={`s-gnb${agentOpen ? ' s-gnb--agent-open' : ''}`}>
      <div className="s-gnb__inner">
        {leftSlot && <div className="s-gnb__left">{leftSlot}</div>}
        <a href="index.html" className="s-gnb__logo-link">
          <img src={DATA.logo} alt="HYPT" className="s-gnb__logo" />
        </a>
        <div className="s-gnb__right">
          <GnbMenu
            activePage={activePage}
            wrapClass="s-gnb__menu-wrap"
            btnClass="s-gnb__menu-btn"
            onAgentChange={setAgentOpen}
          />
        </div>
      </div>
    </header>
  );
}

