/* ===== Shared UI components ===== */
const { useState, useEffect, useRef, useCallback } = React;

/* ---- Icon ---- */
function Icon({ name, size, className }) {
  const p = window.ICONS[name] || '';
  return (
    <svg width={size || 24} height={size || 24} viewBox="0 0 24 24" fill="none" className={className}
      stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"
      dangerouslySetInnerHTML={{ __html: p }} />
  );
}

/* ---- ScaledFrame: renders a section in an isolated iframe, scaled to fit ----
   mode 'crop'  -> fills a fixed box, top-aligned (for cards)
   mode 'fit'   -> shows the whole section, height follows content (for detail) */
function ScaledFrame({ section, theme, logicalWidth, mode, maxScale }) {
  const wrapRef = useRef(null);
  const frameRef = useRef(null);
  const [scale, setScale] = useState(0.26);
  const [contentH, setContentH] = useState(section.height || 480);
  const lw = logicalWidth || 1280;
  const html = window.buildSectionHTML(section);

  // If the section has a user-uploaded thumbnail, show it in card/crop contexts
  // (grid cards, manage rows, category previews) for a consistent representation.
  const hasThumb = !!section.thumb;

  const measure = useCallback(() => {
    const el = wrapRef.current; if (!el) return;
    let s = el.clientWidth / lw;
    if (maxScale) s = Math.min(s, maxScale);
    setScale(s);
  }, [lw, maxScale]);

  useEffect(() => {
    measure();
    const ro = new ResizeObserver(measure);
    if (wrapRef.current) ro.observe(wrapRef.current);
    return () => ro.disconnect();
  }, [measure]);

  const onLoad = () => {
    try {
      const doc = frameRef.current.contentDocument;
      const h = Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight);
      if (h && Math.abs(h - contentH) > 2) setContentH(h);
    } catch (e) {}
  };

  if (mode === 'fit') {
    return (
      <div ref={wrapRef} style={{ width: '100%', height: contentH * scale }}>
        <iframe ref={frameRef} title={section.name} srcDoc={html} onLoad={onLoad}
          style={{ width: lw, height: contentH, border: 'none', transformOrigin: 'top left',
            transform: `scale(${scale})`, background: '#fff', borderRadius: 8 / scale }} />
      </div>
    );
  }
  if (hasThumb) {
    return (
      <div className="scard-clip" style={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
        <img src={section.thumb} alt={section.name} className="scard-thumb-img" loading="lazy" />
      </div>
    );
  }
  return (
    <div ref={wrapRef} className="scard-clip" style={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
      <iframe ref={frameRef} title={section.name} srcDoc={html} onLoad={onLoad} loading="lazy"
        className="scard-frame"
        style={{ width: lw, height: Math.max(contentH, lw * 0.625), transform: `scale(${scale})` }} />
    </div>
  );
}

/* ---- CatDot ---- */
function CatDot({ cat }) {
  return <span className="nav-dot" style={{ background: cat.color }} />;
}

/* ---- MultiCatSelect ---- multi-select category dropdown */
function MultiCatSelect({ cats, setCats }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);

  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); };
  }, [open]);

  const toggle = (id) => setCats(cats.includes(id) ? cats.filter(c => c !== id) : [...cats, id]);
  const label = cats.length === 0 ? 'All categories'
    : cats.length === 1 ? window.catById(cats[0]).label
    : cats.length + ' categories';

  return (
    <div className="mcat" ref={ref}>
      <button className={'mcat-btn' + (open ? ' open' : '') + (cats.length ? ' has' : '')}
        onClick={() => setOpen(o => !o)} aria-expanded={open}>
        <Icon name="filter" size={15} />
        <span className="mcat-label">{label}</span>
        {cats.length > 0 && <span className="mcat-count">{cats.length}</span>}
        <span className="mcat-chev"><Icon name="arrow" size={14} /></span>
      </button>
      {open && (
        <div className="mcat-panel">
          <div className="mcat-panel-head">
            <span>Filter by category</span>
            {cats.length > 0 && <button className="mcat-clear" onClick={() => setCats([])}>Clear all</button>}
          </div>
          <div className="mcat-list">
            {window.CATEGORIES.map(c => {
              const on = cats.includes(c.id);
              return (
                <button key={c.id} className={'mcat-opt' + (on ? ' on' : '')} onClick={() => toggle(c.id)}>
                  <span className="mcat-check">{on && <Icon name="check" size={12} />}</span>
                  <CatDot cat={c} />
                  <span className="mcat-opt-label">{c.label}</span>
                  <span className="mcat-opt-n">{window.catCount(c.id)}</span>
                </button>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

/* ---- SectionCard ---- */
function SectionCard({ section, fav, onFav, onOpen }) {
  const cat = window.catById(section.category);
  return (
    <article className="scard fade-up" onClick={() => onOpen(section)}>
      <div className="scard-preview">
        <ScaledFrame section={section} mode="crop" logicalWidth={1280} />
        <button className={'scard-fav' + (fav ? ' on' : '')}
          onClick={(e) => { e.stopPropagation(); onFav(section.id); }} aria-label="Favorite">
          <Icon name="heart" size={16} />
        </button>
      </div>
      <div className="scard-body">
        <div className="scard-title">
          <h3>{section.name}</h3>
          <div className="scard-title-r">
            {section.pro && <span className="badge pro"><Icon name="star" size={11} /> Pro</span>}
            <button className="btn btn-sm scard-open" onClick={(e) => { e.stopPropagation(); window.openFullPreview(section); }} title="Open full view in new tab">
              <Icon name="external" size={15} /> Open
            </button>
          </div>
        </div>
        <div className="scard-cat"><CatDot cat={cat} /> {cat.label}</div>
        <div className="scard-foot">
          <div className="badges">
            {section.frameworks.includes('html') && <span className="badge html">HTML</span>}
            {section.frameworks.includes('react') && <span className="badge react">React</span>}
          </div>
          <span className="spacer" />
          <span className="scard-stat"><Icon name="download" size={13} /> {(section.downloads / 1000).toFixed(1)}k</span>
        </div>
      </div>
    </article>
  );
}

/* ---- StatCard (dashboard) ---- */
function StatCard({ icon, value, label, delta, tint }) {
  return (
    <div className="statc fade-up">
      <div className="statc-ico" style={{ background: tint + '22', color: tint }}><Icon name={icon} size={19} /></div>
      <div>
        <div className="statc-val">{value}</div>
        <div className="statc-label">{label}</div>
      </div>
      {delta && <div className="statc-delta up"><Icon name="trend" size={13} /> {delta}</div>}
    </div>
  );
}

/* ---- Category tile ---- */
function CatTile({ cat, onOpen }) {
  return (
    <button className="cat-tile fade-up" onClick={() => onOpen(cat)}>
      <div className="cat-tile-ico" style={{ background: cat.color + '1e', color: cat.color }}>
        <Icon name={cat.icon} size={22} />
      </div>
      <div>
        <h3>{cat.label}</h3>
        <span>{window.catCount(cat.id)} {window.catCount(cat.id) === 1 ? 'section' : 'sections'}</span>
      </div>
      <div className="mini-stack"><i></i><i></i><i></i></div>
    </button>
  );
}

/* ---- CatRow (dashboard: vertical category list) ---- */
function CatRow({ cat, onOpen }) {
  const n = window.catCount(cat.id);
  return (
    <button className="cat-row fade-up" onClick={() => onOpen(cat)}>
      <span className="cat-row-ico"><Icon name={cat.icon} size={18} /></span>
      <span className="cat-row-text">
        <span className="cat-row-name">{cat.label}</span>
        <span className="cat-row-blurb">{cat.blurb}</span>
      </span>
      <span className="cat-row-count">{n}</span>
    </button>
  );
}

/* ---- SectionRow (dashboard: tabbed feed — grid card, thumbnail + title only) ---- */
function SectionRow({ section, onOpen, rank }) {
  return (
    <article className="sec-card fade-up" onClick={() => onOpen(section)}>
      <div className="sec-card-thumb">
        <ScaledFrame section={section} mode="crop" logicalWidth={1280} />
        {rank ? <span className="sec-row-rank">{rank}</span> : null}
      </div>
      <h3 className="sec-card-title">{section.name}</h3>
    </article>
  );
}

/* ---- CodePanel ---- */
function CodePanel({ section }) {
  const [tab, setTab] = useState('html');
  const [copied, setCopied] = useState(false);
  const codeRef = useRef(null);
  const code = tab === 'html' ? window.buildSectionHTML(section) : window.buildSectionReact(section);
  const fileName = tab === 'html' ? section.id + '.html' : pascalName(section.id) + '.jsx';

  const copy = () => {
    window.copyToClipboard(code).then((ok) => {
      setCopied(ok ? 'ok' : 'fail');
      if (!ok && codeRef.current) {
        const r = document.createRange(); r.selectNodeContents(codeRef.current);
        const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(r);
      }
      setTimeout(() => setCopied(false), 1800);
    });
  };
  const download = () => {
    if (window.bumpDownloads) window.bumpDownloads();
    const blob = new Blob([code], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a'); a.href = url; a.download = fileName; a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div className="code-panel">
      <div className="code-bar">
        <div className="code-tabs">
          {section.frameworks.includes('html') &&
            <button className={'code-tab' + (tab === 'html' ? ' active' : '')} onClick={() => setTab('html')}>
              <Icon name="code" size={14} /> index<span className="ext">.html</span>
            </button>}
          {section.frameworks.includes('react') &&
            <button className={'code-tab' + (tab === 'react' ? ' active' : '')} onClick={() => setTab('react')}>
              <Icon name="code" size={14} /> {pascalName(section.id)}<span className="ext">.jsx</span>
            </button>}
        </div>
        <button className="code-copy" onClick={download} style={{ marginRight: 6 }}>
          <Icon name="download" size={14} /> Download
        </button>
        <button className={'code-copy' + (copied === 'ok' ? ' done' : '')} onClick={copy} title="Copy the full source">
          <Icon name={copied === 'ok' ? 'check' : 'copy'} size={14} /> {copied === 'ok' ? 'Copied!' : copied === 'fail' ? 'Press ⌘C' : 'Copy code'}
        </button>
      </div>
      <div className="code-scroll">
        <pre><code ref={codeRef} dangerouslySetInnerHTML={{ __html: window.highlightCode(code, tab) }} /></pre>
      </div>
    </div>
  );
}

function pascalName(id) {
  return id.split(/[-_]/).map(p => p.charAt(0).toUpperCase() + p.slice(1)).join('');
}

function initials(name) {
  return (name || '?').trim().split(/\s+/).slice(0, 2).map(w => w[0]).join('').toUpperCase();
}

/* Opens a section's rendered HTML in a brand-new browser tab (full view). */
function openFullPreview(section) {
  try {
    const html = window.buildSectionHTML(section);
    const blob = new Blob([html], { type: 'text/html' });
    const url = URL.createObjectURL(blob);
    const w = window.open(url, '_blank', 'noopener');
    setTimeout(() => URL.revokeObjectURL(url), 60000);
    if (!w) { // popup blocked — fall back to a data navigation
      const a = document.createElement('a'); a.href = url; a.target = '_blank'; a.rel = 'noopener'; a.click();
    }
  } catch (e) {}
}

Object.assign(window, { Icon, ScaledFrame, CatDot, MultiCatSelect, SectionCard, StatCard, CatTile, CatRow, SectionRow, CodePanel, pascalName, openFullPreview, initials });
