/* Shared hooks and small bits */

// Scroll-reveal hook — IntersectionObserver with a fallback for environments
// where IO doesn't fire reliably (iframes, headless capture). After a short
// timeout, any reveal element that's already in the viewport gets force-shown.
function useReveal() {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let shown = false;
    const show = () => { if (shown) return; shown = true; el.classList.add('in'); };

    // If element is already within viewport at mount, just show it after a beat.
    const tryNow = () => {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight && r.bottom > 0) show();
    };

    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) show(); });
    }, { threshold: 0.05, rootMargin: '0px 0px -5% 0px' });
    io.observe(el);

    // Fallback: after a tick, force-show anything already on-screen.
    const t = setTimeout(tryNow, 120);

    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
  return ref;
}

function Reveal({ children, delay = 0, as: As = 'div', className = '', ...rest }) {
  const ref = useReveal();
  const style = delay ? { transitionDelay: `${delay}ms` } : undefined;
  return (
    <As ref={ref} className={`reveal ${className}`} style={style} {...rest}>
      {children}
    </As>
  );
}

// Magnetic button — element shifts slightly toward the cursor
function Magnetic({ children, strength = 18, className = '', ...rest }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = e.clientX - (r.left + r.width / 2);
    const y = e.clientY - (r.top + r.height / 2);
    el.style.transform = `translate(${(x / r.width) * strength}px, ${(y / r.height) * strength}px)`;
  };
  const onLeave = () => { if (ref.current) ref.current.style.transform = ''; };
  return (
    <span
      ref={ref}
      onMouseMove={onMove}
      onMouseLeave={onLeave}
      style={{ display: 'inline-block', transition: 'transform 0.25s cubic-bezier(.2,.7,.2,1)' }}
      className={className}
      {...rest}
    >
      {children}
    </span>
  );
}

// Typing effect — types a string char by char, then optionally calls onDone
function useTyping(text, { speed = 18, start = true, onDone } = {}) {
  const [out, setOut] = React.useState('');
  React.useEffect(() => {
    if (!start) return;
    setOut('');
    let i = 0;
    let cancelled = false;
    const tick = () => {
      if (cancelled) return;
      i += 1;
      setOut(text.slice(0, i));
      if (i < text.length) setTimeout(tick, speed);
      else if (onDone) onDone();
    };
    const t = setTimeout(tick, speed);
    return () => { cancelled = true; clearTimeout(t); };
  }, [text, start]);
  return out;
}

// Window utilities
const DEFAULT_ROUTE_PATHS = {
  home: '/',
  about: '/about/',
  services: '/services/',
  cases: '/cases/',
  articles: '/articles/',
  prices: '/prices/',
  platforms: '/platforms/',
  contact: '/contact/',
};

function routeHref(id) {
  return (window.__ROUTE_PATHS__ || DEFAULT_ROUTE_PATHS)[id] || `/${id}/`;
}

function routeClick(setRoute, id) {
  return (e) => {
    if (typeof setRoute !== 'function') return;
    e.preventDefault();
    setRoute(id);
    window.scrollTo(0, 0);
  };
}

function getBrandData() {
  const contact = window.__PUBLIC_DATA__?.contact || {};
  const name = String(contact.site_name || 'Winet Lab').trim() || 'Winet Lab';
  const domain = String(contact.site_label || '').trim() || 'app.winetlab.site';
  return {
    name,
    domain,
    icon: '/favicon.png',
    iconLight: '/favicon-light.png',
  };
}

function BrandMark() {
  const brand = getBrandData();
  return (
    <span className="brand-mark-2" aria-hidden="true">
      <img src={brand.icon} data-brand-icon data-dark-src={brand.icon} data-light-src={brand.iconLight} alt="" />
    </span>
  );
}

function BrandText({ showDomain = true } = {}) {
  const brand = getBrandData();
  return (
    <span className="brand-text-2">
      <span className="brand-name-2">{brand.name}</span>
      {showDomain && brand.domain ? <span className="brand-domain-2">{` \u00b7 ${brand.domain}`}</span> : null}
    </span>
  );
}

function BrandLink({ href = '/', onClick, className = 'brand', showDomain = true } = {}) {
  return (
    <a href={href} onClick={onClick} className={className} aria-label="На главную">
      <BrandMark />
      <BrandText showDomain={showDomain} />
    </a>
  );
}

function FooterBrand({ style } = {}) {
  const brand = getBrandData();
  return (
    <div className="brand-2" style={style}>
      <BrandMark />
      <span className="brand-name-2">{brand.name}</span>
    </div>
  );
}

function scrollToId(id) {
  const el = document.getElementById(id);
  if (!el) return;
  const top = el.getBoundingClientRect().top + window.scrollY - 70;
  window.scrollTo({ top, behavior: 'smooth' });
}

Object.assign(window, {
  useReveal,
  Reveal,
  Magnetic,
  useTyping,
  routeHref,
  routeClick,
  getBrandData,
  BrandMark,
  BrandText,
  BrandLink,
  FooterBrand,
  scrollToId,
});
