const QDS = () => window.QuintescenceDesignSystem_1868a3;
const KEY = '#641124';
const TORN = n => `assets/textures/torn/tornpaper${n}.webp`;

// Papier déchiré teinté (texture multipliée + découpe du bord)
function Paper({ n = 4, color = 'var(--q-creme)', children, className = '', style, innerStyle, ...rest }) {
  const u = `url(${TORN(n)})`;
  return <div className={'paper ' + className} style={style} {...rest}>
    <div className="paper-in" style={{ background: `linear-gradient(color-mix(in srgb, ${color} 86%, transparent), color-mix(in srgb, ${color} 86%, transparent)), ${u} center/100% 100% no-repeat`, WebkitMaskImage: u, maskImage: u, ...innerStyle }}>{children}</div>
  </div>;
}
// Bande pleine largeur à bords déchirés
function TornBand({ color = 'var(--q-creme)', top = true, bottom = true, children, className = '', style, ...rest }) {
  return <section className={'band ' + className} style={{ '--band': color, ...style }} {...rest}>
    {top && <i className="edge top" aria-hidden="true"></i>}{children}{bottom && <i className="edge bot" aria-hidden="true"></i>}
  </section>;
}
function Eyebrow({ children, color = 'var(--q-peach)', style }) { return <div className="q-tagline" style={{ color, ...style }}>{children}</div>; }
function Words({ text, as = 'span', style, className = '', step = 0.04 }) {
  const T = as;
  return <T data-words="" className={'words ' + className} style={style}>{text.split(' ').map((w, i) => <React.Fragment key={i}><span className="w" style={{ '--d': (i * step).toFixed(2) + 's' }}><span>{w}</span></span>{' '}</React.Fragment>)}</T>;
}
const ORN_FILE = k => k === 'pois' ? 'pois.png' : k.startsWith('sticker-') ? k + '.png' : k === 'gribouillis' ? 'gribouillis.svg' : k + '-vectorizely.svg';
const Orn = ({ k, cls = '', style }) => <img src={'assets/elements/' + ORN_FILE(k)} alt="" aria-hidden="true" className={'orn ' + cls} style={style}></img>;
const Ic = (name, size = 18, color) => React.createElement(QDS().Icon, { name, size, color });

function go(id) { const el = document.getElementById(id); if (el) scrollTo({ top: el.getBoundingClientRect().top + scrollY - 70, behavior: 'smooth' }); }
const link = id => ({ href: '#' + id, onClick: e => { e.preventDefault(); go(id); } });

function useDevice() {
  const [d, setD] = React.useState(window.QDEVICE || 'desktop');
  React.useEffect(() => { const f = () => setD(window.QDEVICE); addEventListener('devicechange', f); return () => removeEventListener('devicechange', f); }, []);
  return d;
}

function useScrollEngine() {
  React.useEffect(() => {
    let raf, key = '';
    const tick = () => {
      const vh = innerHeight, sh = document.documentElement.scrollHeight, k = scrollY + '|' + vh + '|' + sh;
      if (k !== key) {
        key = k;
        const max = sh - vh, bar = document.querySelector('.progress');
        if (bar) bar.style.transform = 'scaleX(' + (max > 0 ? scrollY / max : 0).toFixed(4) + ')';
        const pins = [...document.querySelectorAll('[data-pin]')], pars = [...document.querySelectorAll('[data-par]')];
        const pr = pins.map(el => el.getBoundingClientRect()), qr = pars.map(el => el.getBoundingClientRect());
        pins.forEach((el, i) => { const r = pr[i], st = el.querySelector('.sticky'), sv = st && getComputedStyle(st).position === 'sticky' ? st.offsetHeight : vh; el.style.setProperty('--p', Math.max(0, Math.min(1, -r.top / Math.max(1, r.height - sv))).toFixed(4)); });
        pars.forEach((el, i) => { const r = qr[i]; el.style.setProperty('--o', Math.max(-1.5, Math.min(1.5, (r.top + r.height / 2 - vh / 2) / vh)).toFixed(4)); });
      }
      raf = requestAnimationFrame(tick);
    };
    tick();
    const io = new IntersectionObserver(es => es.forEach(e => { if (e.isIntersecting) e.target.classList.add('in'); }), { threshold: 0.18 });
    const lo = new IntersectionObserver(es => es.forEach(e => e.target.classList.toggle('live', e.isIntersecting)), { rootMargin: '100px 0px' });
    document.querySelectorAll('[data-loop]').forEach(el => lo.observe(el));
    const scan = () => document.querySelectorAll('[data-reveal]:not([data-obs]),[data-words]:not([data-obs])').forEach(el => { el.setAttribute('data-obs', ''); io.observe(el); });
    scan(); const mo = new MutationObserver(scan); mo.observe(document.body, { childList: true, subtree: true });
    return () => { cancelAnimationFrame(raf); io.disconnect(); lo.disconnect(); mo.disconnect(); };
  }, []);
}

// Garde un élément monté le temps de son animation de sortie
function useLeave(value, ms = 180) {
  const [shown, setShown] = React.useState(value || null), [leaving, setLeaving] = React.useState(false);
  React.useEffect(() => {
    if (value) { setShown(value); setLeaving(false); return; }
    if (!shown) return;
    setLeaving(true); const t = setTimeout(() => { setShown(null); setLeaving(false); }, ms); return () => clearTimeout(t);
  }, [value]);
  return [shown, leaving];
}

function Header({ count = 0, onCart }) {
  const { Button } = QDS();
  const [hidden, setHidden] = React.useState(false), [solid, setSolid] = React.useState(false), [menu, setMenu] = React.useState(false);
  const [menuShown, menuLeaving] = useLeave(menu, 150);
  React.useEffect(() => { let last = 0; const f = () => { const y = scrollY; setHidden(y > last && y > 400 && !menu); setSolid(y > 60); last = y; }; addEventListener('scroll', f, { passive: true }); return () => removeEventListener('scroll', f); }, [menu]);
  const nav = [['Univers', 'univers'], ['Créateurs', 'createurs'], ['Showroom 3D', 'showroom'], ['Notre histoire', 'histoire']];
  return <header className={'hdr' + (hidden ? ' hide' : '') + (solid || menu ? ' solid' : '')}>
    <i className="hdr-bg" aria-hidden="true"></i>
    <div className="hdr-in">
      <a href="#top" onClick={e => { e.preventDefault(); scrollTo({ top: 0, behavior: 'smooth' }); }} className="hdr-logo" aria-label="Quintescence, accueil"><img src="assets/logo/quintescence-logo-couleur.svg" alt="Quintescence — Bijoux • Accessoires • Vêtements"></img></a>
      <nav className="hdr-nav">{nav.map(([l, id]) => <a key={id} {...link(id)}>{l}</a>)}</nav>
      <div className="hdr-right">
        <Button variant="fuchsia" size="sm" className="hide-sm" iconLeft={Ic('map-pin', 15, 'var(--q-creme)')} onClick={() => go('visite')}>Nous rendre visite</Button>
        <CartButton count={count} onClick={onCart}></CartButton>
        <button className="burger" onClick={() => setMenu(!menu)} aria-label="Menu" aria-expanded={menu}>{Ic(menu ? 'x' : 'menu', 22, 'var(--q-bordeaux-chic)')}</button>
      </div>
    </div>
    {menuShown && <Paper n={12} className={'mob-menu' + (menuLeaving ? ' out' : '')} innerStyle={{ padding: '36px 42px' }}>{[...nav, ['Nous rendre visite', 'visite']].map(([l, id]) => <a key={id} href={'#' + id} onClick={e => { e.preventDefault(); setMenu(false); go(id); }}>{l}</a>)}</Paper>}
  </header>;
}

function Modal({ onClose, children, width = 920, n = 12, leaving }) {
  React.useEffect(() => { const k = e => e.key === 'Escape' && onClose(); addEventListener('keydown', k); return () => removeEventListener('keydown', k); }, []);
  return <div className={'scrim' + (leaving ? ' out' : '')} onClick={onClose}><div className="qv" style={{ maxWidth: width }} onClick={e => e.stopPropagation()} role="dialog" aria-modal="true">
    <Paper n={n} innerStyle={{ padding: 'clamp(44px,6vw,66px) clamp(34px,6vw,64px)' }}>
      <button className="x" onClick={onClose} aria-label="Fermer">{Ic('x', 20, 'var(--q-bordeaux-chic)')}</button>
      {children}
    </Paper>
  </div></div>;
}

function QuickView({ p: cur, onClose, onAdd }) {
  const { Button, Badge, Tape } = QDS();
  const [p, leaving] = useLeave(cur, 160);
  if (!p) return null;
  const u = UNIVERS.find(x => x.id === p.u);
  return <Modal onClose={onClose} leaving={leaving}>
    <div className="qv-grid">
      <div className="qv-img"><img src={p.img} alt={p.name}></img><Tape n={4} width={120} rotate={-7} style={{ position: 'absolute', top: -14, left: '30%' }}></Tape></div>
      <div className="qv-copy">
        {p.badge && <Badge tone={p.tone} style={{ alignSelf: 'flex-start' }}>{p.badge}</Badge>}
        <Eyebrow color="var(--q-fuchsia)">{p.brand} · {u.t}</Eyebrow>
        <h3 className="h3">{p.name}</h3>
        <div className="qv-price">{fmt(p.price)}</div>
        <p className="body">{p.desc}</p>
        <div className="row">
          <Button variant="cta" size="lg" iconLeft={Ic('shopping-bag', 16, '#fff')} onClick={() => { onAdd(p); onClose(); }}>Ajouter au panier</Button>
        </div>
        <div className="avail">{Ic('store', 18, 'var(--q-fuchsia)')}<span>Aussi disponible en boutique, 68 rue Mirebeau</span></div>
      </div>
    </div>
  </Modal>;
}

function Legal({ open, onClose }) {
  const [isOpen, leaving] = useLeave(open, 160);
  if (!isOpen) return null;
  const rows = [['Éditeur du site', 'Entreprise AUBAILLY (EURL)'], ['Enseigne commerciale', 'QUINTESCENCE'], ['Siège social', '68 Rue Mirebeau, 18000 Bourges'], ['Capital social', '3 000,00 €'], ['Immatriculation', 'RCS Bourges n° 978 297 414'], ['SIRET', '978 297 414 00010'], ['TVA Intracommunautaire', 'FR17978297414'], ['Directrice de la publication', 'Morgane Aubailly (Gérante)'], ['Hébergeur', 'À renseigner']];
  return <Modal onClose={onClose} width={640} n={18} leaving={leaving}>
    <div style={{ paddingLeft: 'clamp(0px,6%,40px)' }}>
      <h3 className="h3">Mentions légales</h3>
      <dl className="legal">{rows.map(([k, v]) => <React.Fragment key={k}><dt>{k}</dt><dd>{v}</dd></React.Fragment>)}</dl>
    </div>
  </Modal>;
}

function JewelPanel({ jewel, onPick }) {
  const [isOpen, setOpen] = React.useState(false);
  const models = (window.QJewel && window.QJewel.models) || [];
  return <div className={'jp' + (isOpen ? ' open' : '')}>
    <button className="jp-btn" onClick={() => setOpen(!isOpen)} aria-expanded={isOpen}><img src="assets/elements/etoile-vectorizely.svg" alt="" width="22"></img>Bijou 3D</button>
    <div className="jp-panel">
      <Paper n={19} innerStyle={{ padding: '38px 36px' }}>
        <Eyebrow color="var(--q-fuchsia)">Bijou affiché sur le site</Eyebrow>
        <div className="jp-list">{models.map((m, i) => <button key={m.id} className={'jp-item' + (jewel === m.id ? ' on' : '')} onClick={() => onPick(m.id)}><span className="jp-n">0{i + 1}</span>{m.label}</button>)}</div>
      </Paper>
    </div>
  </div>;
}

function Intro({ onDone }) {
  const v = React.useRef(null);
  const [out, setOut] = React.useState(false), [playing, setPlaying] = React.useState(false), [muted, setMuted] = React.useState(true), [t, setT] = React.useState(0), [d, setD] = React.useState(0);
  const end = () => { if (out) return; document.documentElement.classList.add('ready'); setOut(true); setTimeout(onDone, 900); };
  React.useEffect(() => { const el = v.current; if (!el) return; el.muted = true; el.play().then(() => setPlaying(true)).catch(() => setPlaying(false)); }, []);
  const toggle = () => { const el = v.current; if (el.paused) { el.play(); setPlaying(true); } else { el.pause(); setPlaying(false); } };
  const setMute = m => { const el = v.current; el.muted = m; setMuted(m); if (!m && el.paused) { el.play(); setPlaying(true); } };
  const seek = e => { const r = e.currentTarget.getBoundingClientRect(); v.current.currentTime = ((e.clientX - r.left) / r.width) * (d || 0); };
  return <div className={'intro' + (out ? ' out' : '')}>
    <video ref={v} src="assets/video/intro-v5.mp4" playsInline preload="auto" onTimeUpdate={e => setT(e.target.currentTime)} onLoadedMetadata={e => setD(e.target.duration)} onEnded={end} onClick={toggle}></video>
    <div className="iv-bar">
      <div className="iv-track" onClick={seek}><span style={{ transform: `scaleX(${d ? t / d : 0})` }}></span></div>
      <div className="iv-row">
        <button className="iv-btn" onClick={toggle} aria-label={playing ? 'Pause' : 'Lecture'}>{Ic(playing ? 'pause' : 'play', 16, 'var(--q-creme)')}</button>
        <button className="iv-btn" onClick={() => setMute(!muted)} aria-label={muted ? 'Activer le son' : 'Couper le son'}>{Ic(muted ? 'volume-x' : 'volume-2', 18, 'var(--q-creme)')}</button>
        <button className="iv-skip" onClick={end}>Passer l'intro</button>
      </div>
    </div>
  </div>;
}

Object.assign(window, { useDevice, useLeave, QDS, KEY, TORN, Paper, TornBand, Eyebrow, Words, Orn, Ic, go, link, useScrollEngine, Header, QuickView, Legal, JewelPanel, Intro });
