/* SMILE ROOM — Web UI kit · shared cosmetic components
 * Self-contained recreations that consume the design tokens (styles.css)
 * and Phosphor Thin icons. Exposed on window for the index app script.
 */

/* ---- Cinematic animation infrastructure ---- */
const ensureAnimStyle = () => {
  if (typeof document === 'undefined' || document.getElementById('sr-anim-style')) return;
  const el = document.createElement('style');
  el.id = 'sr-anim-style';
  el.textContent = `
  .reveal{opacity:0;transform:translateY(38px);filter:blur(6px);
    transition:opacity .9s var(--ease-out),transform 1s var(--ease-out),filter .9s var(--ease-out);
    transition-delay:var(--reveal-delay,0ms);will-change:opacity,transform}
  .reveal.is-in{opacity:1;transform:none;filter:blur(0)}
  .reveal-fade{opacity:0;transition:opacity 1.1s var(--ease-out);transition-delay:var(--reveal-delay,0ms)}
  .reveal-fade.is-in{opacity:1}
  .reveal-scale{opacity:0;transform:scale(1.06);
    transition:opacity 1.1s var(--ease-out),transform 1.4s var(--ease-out);transition-delay:var(--reveal-delay,0ms)}
  .reveal-scale.is-in{opacity:1;transform:none}
  @keyframes sr-kenburns{0%{transform:scale(1.04)}100%{transform:scale(1.16)}}
  @keyframes sr-scrolldot{0%,100%{transform:translateY(0);opacity:.3}50%{transform:translateY(8px);opacity:1}}
  @media (prefers-reduced-motion: reduce){
    .reveal,.reveal-fade,.reveal-scale{opacity:1!important;transform:none!important;filter:none!important;transition:none!important}
  }`;
  document.head.appendChild(el);
};

/** Reveal-on-scroll wrapper — animates IN on enter, OUT on leave (entrada y salida). */
const Reveal = ({ children, variant = '', delay = 0, once = false, style, ...rest }) => {
  ensureAnimStyle();
  const ref = React.useRef(null);
  React.useEffect(() => {
    const node = ref.current;
    if (!node) return;
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { node.classList.add('is-in'); return; }
    let done = false, ticking = false;
    const check = () => {
      ticking = false;
      const r = node.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      const visible = r.top < vh * 0.9 && r.bottom > vh * 0.06;
      if (visible) {
        node.classList.add('is-in');
        if (once) { done = true; window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); }
      } else if (!once) {
        node.classList.remove('is-in');
      }
    };
    const onScroll = () => {
      if (done) return;
      check();                                   // direct — reliable even if rAF is throttled
      if (!ticking) { ticking = true; requestAnimationFrame(check); }
    };
    check();                                      // initial (layout is ready post-mount)
    setTimeout(check, 80);                        // re-check after fonts/layout settle
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); };
  }, [once]);
  const cls = variant === 'fade' ? 'reveal-fade' : variant === 'scale' ? 'reveal-scale' : 'reveal';
  return (
    <div ref={ref} className={cls} style={{ '--reveal-delay': `${delay}ms`, ...style }} {...rest}>
      {children}
    </div>
  );
};

/** Parallax hook — translateY proportional to element's offset from viewport center. */
const useParallax = (speed = 0.18) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    const node = ref.current;
    if (!node) return;
    let raf = null;
    const update = () => {
      raf = null;
      const r = node.getBoundingClientRect();
      const center = r.top + r.height / 2 - window.innerHeight / 2;
      node.style.transform = `translate3d(0, ${(-center * speed).toFixed(1)}px, 0)`;
    };
    const onScroll = () => { if (raf == null) raf = requestAnimationFrame(update); };
    update();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); if (raf) cancelAnimationFrame(raf); };
  }, [speed]);
  return ref;
};

/** Viewport hook — drives responsive layout switches. */
const useViewport = () => {
  const [w, setW] = React.useState(typeof window !== 'undefined' ? window.innerWidth : 1280);
  React.useEffect(() => {
    let t = null;
    const on = () => { if (t) return; t = setTimeout(() => { t = null; setW(window.innerWidth); }, 80); };
    window.addEventListener('resize', on, { passive: true });
    setW(window.innerWidth);
    return () => { window.removeEventListener('resize', on); if (t) clearTimeout(t); };
  }, []);
  return { w, isMobile: w < 760, isTablet: w >= 760 && w < 1040 };
};

const KBtn = ({ children, variant = 'primary', size = 'md', icon, iconRight, disabled, style, ...rest }) => {
  const sizes = {
    sm: { height: 42, padding: '0 1.8em', fontSize: 11.5, gap: '.6em' },
    md: { height: 50, padding: '0 2.1em', fontSize: 12.5, gap: '.65em' },
    lg: { height: 58, padding: '0 2.6em', fontSize: 13.5, gap: '.7em' },
  }[size] || {};
  /* sh = sombra en reposo · shH = sombra en hover (incluye el borde inset cuando aplica) */
  const V = {
    primary: { bg: 'var(--carbon)', color: 'var(--linen-50)', sh: 'var(--shadow-sm)', shH: 'var(--shadow-md)' },
    gold: { bg: 'var(--grad-gold)', color: 'var(--carbon)', sh: 'var(--shadow-xs)', shH: 'var(--shadow-gold)' },
    outline: { bg: 'transparent', color: 'var(--carbon)', sh: 'inset 0 0 0 1.5px var(--line-strong)', shH: 'inset 0 0 0 1.5px var(--carbon), var(--shadow-sm)' },
    light: { bg: 'transparent', color: 'var(--linen-50)', sh: 'inset 0 0 0 1.5px rgba(255,255,255,.5)', shH: 'inset 0 0 0 1.5px rgba(255,255,255,.92), 0 8px 22px rgba(0,0,0,.22)' },
    ghost: { bg: 'transparent', color: 'var(--text-gold)', sh: 'none', shH: 'none' },
  }[variant];
  const base = {
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: sizes.gap,
    height: sizes.height, padding: sizes.padding, border: 'none', cursor: disabled ? 'not-allowed' : 'pointer',
    fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: sizes.fontSize,
    letterSpacing: '.16em', textTransform: 'uppercase', whiteSpace: 'nowrap', lineHeight: 1,
    borderRadius: 'var(--radius-sm)', transition: 'transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out)',
    background: V.bg, color: V.color, boxShadow: V.sh, opacity: disabled ? 0.4 : 1,
  };
  const enter = e => { if (disabled) return; e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = V.shH; };
  const reset = e => { e.currentTarget.style.transform = 'none'; e.currentTarget.style.boxShadow = V.sh; };
  const down = e => { if (disabled) return; e.currentTarget.style.transform = 'translateY(1px)'; };
  return (
    <button disabled={disabled} style={{ ...base, ...style }}
      onMouseEnter={enter} onMouseLeave={reset} onMouseDown={down} onMouseUp={enter} {...rest}>
      {icon && <i className={icon} style={{ fontSize: '1.3em', lineHeight: 0 }} />}
      {children && <span>{children}</span>}
      {iconRight && <i className={iconRight} style={{ fontSize: '1.3em', lineHeight: 0 }} />}
    </button>
  );
};

const Eyebrow = ({ children, light }) => (
  <span style={{
    fontFamily: 'var(--font-display)', fontSize: '12px', fontWeight: 500,
    letterSpacing: '.22em', textTransform: 'uppercase',
    color: light ? 'var(--champagne-300)' : 'var(--text-gold)',
  }}>{children}</span>
);

const Rule = ({ width = 200, center }) => (
  <div style={{ display: 'flex', alignItems: 'center', gap: '12px', width, margin: center ? '0 auto' : undefined }}>
    <span style={{ flex: 1, height: 1, background: 'var(--line-gold)' }} />
    <span style={{ width: 6, height: 6, transform: 'rotate(45deg)', background: 'var(--champagne-400)' }} />
    <span style={{ flex: 1, height: 1, background: 'var(--line-gold)' }} />
  </div>
);

const Wordmark = ({ size = 26, light, tagline = true }) => (
  <span className="sr-wordmark" style={{ fontSize: size, color: light ? 'var(--linen-50)' : 'var(--carbon)' }}>
    SMILE&nbsp;ROOM
    {tagline && <span className="sr-wordmark__tag" style={light ? { color: 'var(--champagne-300)' } : null}>Odontología Digital Avanzada</span>}
  </span>
);

const SectionHeading = ({ eyebrow, title, subtitle, center, rule, light }) => (
  <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', alignItems: center ? 'center' : 'flex-start', textAlign: center ? 'center' : 'left' }}>
    {eyebrow && <Eyebrow light={light}>{eyebrow}</Eyebrow>}
    <h2 style={{
      fontFamily: 'var(--font-display)', fontWeight: 300, letterSpacing: '.14em',
      textTransform: 'uppercase', color: light ? 'var(--linen-50)' : 'var(--text-strong)',
      lineHeight: 1.18, margin: 0, fontSize: 'clamp(26px, 3vw, 40px)',
    }}>{title}</h2>
    {rule && <Rule center={center} />}
    {subtitle && <p style={{
      fontSize: '17px', lineHeight: 1.65, color: light ? 'rgba(255,255,255,.66)' : 'var(--text-muted)',
      maxWidth: '56ch', margin: center ? '0 auto' : 0,
    }}>{subtitle}</p>}
  </div>
);

Object.assign(window, { KBtn, Eyebrow, Rule, Wordmark, SectionHeading, Reveal, useParallax, useViewport });
