// Section components for atouchmoment.com — apple-style keynote scroll
const { useState, useEffect, useRef, useMemo } = React;

// Resolve an asset path to a bundled blob URL (window.__resources) when present.
function res(path) {
  if (!path) return path;
  const map = window.__resources || {};
  if (path.indexOf("about-concert") >= 0 && map.aboutImg) return map.aboutImg;
  if (path.indexOf("qloze-app") >= 0 && map.qlozeApp) return map.qlozeApp;
  if (path.indexOf("garland") >= 0 && map.garlandImg) return map.garlandImg;
  if (path.indexOf("letters") >= 0 && map.lettersImg) return map.lettersImg;
  if (path.indexOf("hologram") >= 0 && map.hologramImg) return map.hologramImg;
  if (path.indexOf("qr2shot") >= 0 && map.qr2shotImg) return map.qr2shotImg;
  return path;
}

// ---------- scroll engine ----------
const REDUCED_MOTION = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

const clamp01 = (v) => Math.max(0, Math.min(1, v));

// Single rAF-throttled scroll/resize dispatcher (window + inner scrollers via capture)
const ScrubBus = (() => {
  const fns = new Set();
  let ticking = false;
  function run() {
    ticking = false;
    fns.forEach((f) => f());
  }
  function request() {
    if (!ticking) {
      ticking = true;
      requestAnimationFrame(run);
    }
  }
  document.addEventListener("scroll", request, { capture: true, passive: true });
  window.addEventListener("resize", request, { passive: true });
  return {
    add(fn) { fns.add(fn); request(); },
    remove(fn) { fns.delete(fn); },
    request,
  };
})();

function useScrub(fn) {
  useEffect(() => {
    if (REDUCED_MOTION) return;
    ScrubBus.add(fn);
    return () => ScrubBus.remove(fn);
  }, []);
}

// Progress through a pinned (taller-than-viewport) section: 0 at top, 1 fully scrolled
function usePin(ref, varName = "--p") {
  useScrub(() => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const vh = window.innerHeight;
    const range = Math.max(1, r.height - vh);
    el.style.setProperty(varName, clamp01(-r.top / range).toFixed(4));
  });
}

// Travel progress: 0 when element enters bottom of viewport, 1 when it leaves the top
function useTravel(ref, varName = "--t") {
  useScrub(() => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const vh = window.innerHeight;
    el.style.setProperty(varName, clamp01((vh - r.top) / (vh + r.height)).toFixed(4));
  });
}

// Global page progress → nav hairline (--gp on <html>)
function GlobalProgress() {
  useScrub(() => {
    const doc = document.documentElement;
    const scroller = document.querySelector(".atm-mobile__viewport");
    const top = scroller ? scroller.scrollTop : (window.scrollY || doc.scrollTop);
    const h = scroller
      ? scroller.scrollHeight - scroller.clientHeight
      : doc.scrollHeight - window.innerHeight;
    doc.style.setProperty("--gp", clamp01(top / Math.max(1, h)).toFixed(4));
  });
  return null;
}

// Thai-aware word segmentation for the manifesto scrub
function segmentWords(text, lang) {
  if (typeof Intl !== "undefined" && Intl.Segmenter) {
    try {
      const seg = new Intl.Segmenter(lang === "th" ? "th" : "en", { granularity: "word" });
      const out = [];
      for (const s of seg.segment(text)) out.push(s.segment);
      // merge whitespace into the previous chunk so spans stay tidy
      return out.reduce((acc, cur) => {
        if (!cur.trim() && acc.length) acc[acc.length - 1] += cur;
        else acc.push(cur);
        return acc;
      }, []);
    } catch (e) { /* fall through */ }
  }
  return text.split(/(\s+)/).filter(Boolean).reduce((acc, cur) => {
    if (!cur.trim() && acc.length) acc[acc.length - 1] += cur;
    else acc.push(cur);
    return acc;
  }, []);
}

const HL_RE = /valuable|asset|สินทรัพย์|มีค่า/i;

// IntersectionObserver-based fade-in wrapper
function Reveal({ children, delay = 0, as: As = "div", className = "", style = {}, ...rest }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (REDUCED_MOTION) { setSeen(true); return; }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
    }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <As ref={ref} className={"atm-reveal " + (seen ? "is-in " : "") + className} style={{ transitionDelay: delay + "ms", ...style }} {...rest}>
      {children}
    </As>
  );
}

// ---------- HERO (pinned, scrubs out) ----------
function Hero({ t }) {
  const ref = useRef(null);
  usePin(ref);
  return (
    <section className="atm-hero" id="top" ref={ref}>
      <div className="atm-hero__pin">
        <div className="atm-hero__mesh" aria-hidden="true">
          <span className="atm-mesh atm-mesh--a"></span>
          <span className="atm-mesh atm-mesh--b"></span>
          <span className="atm-mesh atm-mesh--c"></span>
          <span className="atm-grain"></span>
        </div>
        <div className="atm-hero__inner">
          <Reveal as="p" className="atm-eyebrow">{t.hero.eyebrow}</Reveal>
          <h1 className="atm-hero__h1">
            <Reveal as="span" delay={80}><span>{t.hero.headline_l1}</span></Reveal>
            <Reveal as="span" delay={180}><span>{t.hero.headline_l2}</span></Reveal>
            <Reveal as="span" delay={280}><span className="atm-hero__line3"><em>{t.hero.headline_l3}</em></span></Reveal>
          </h1>
          <Reveal as="p" delay={420} className="atm-hero__sub">{t.hero.sub}</Reveal>
          <Reveal delay={520} className="atm-hero__ctas">
            <a href="#about" className="atm-btn atm-btn--primary">{t.hero.cta1}</a>
            <a href="#products" className="atm-btn atm-btn--ghost">{t.hero.cta2}</a>
          </Reveal>
        </div>
        <div className="atm-hero__scrollcue" aria-hidden="true">scroll</div>
      </div>
    </section>
  );
}

// ---------- MANIFESTO (word-by-word scrub) ----------
function Manifesto({ t, lang }) {
  const ref = useRef(null);
  usePin(ref);
  const words = useMemo(() => segmentWords(t.about.body1, lang), [t, lang]);
  return (
    <section className="atm-manifesto" ref={ref}>
      <div className="atm-manifesto__pin">
        <p className="atm-eyebrow">{t.about.eyebrow}</p>
        <p className="atm-manifesto__text" style={{ "--n": words.length }}>
          {words.map((w, i) => (
            <span key={i} className={"atm-w" + (HL_RE.test(w) ? " atm-w--hl" : "")} style={{ "--i": i }}>{w}</span>
          ))}
        </p>
      </div>
    </section>
  );
}

// ---------- ABOUT (bento) ----------
function About({ t }) {
  const visRef = useRef(null);
  useTravel(visRef);
  return (
    <section className="atm-section atm-about" id="about">
      <div className="atm-chapter-head">
        <Reveal as="p" className="atm-eyebrow">{t.about.eyebrow}</Reveal>
        <Reveal as="h2" delay={80} className="atm-section__h2">
          {t.about.title.split("\n").map((l, i) => <span key={i}>{l}</span>)}
        </Reveal>
      </div>
      <div className="atm-about__grid">
        <Reveal delay={120} className="atm-card atm-about__body">
          <p className="atm-lead">{t.about.body2}</p>
          <p>{t.about.body3}</p>
        </Reveal>
        <Reveal delay={200} className="atm-card atm-about__visual">
          <div className="atm-about__visual-inner" ref={visRef}>
            <img src={res("assets/about-concert.png")} alt="Artist on stage reaching out to fans, connected through the a touch moment app" loading="lazy" />
          </div>
        </Reveal>
        <div className="atm-about__stats">
          {[t.about.stat1, t.about.stat2, t.about.stat3].map((s, i) => (
            <Reveal key={i} delay={140 + i * 90} className="atm-card atm-stat">
              <span className="atm-stat__n">{s[0]}</span>
              <span className="atm-stat__l">{s[1]}</span>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

// ---------- BELIEVE ----------
function Believe({ t }) {
  return (
    <section className="atm-section atm-believe" id="believe">
      <div className="atm-chapter-head">
        <Reveal as="p" className="atm-eyebrow">{t.believe.eyebrow}</Reveal>
        <Reveal as="h2" delay={80} className="atm-section__h2">{t.believe.title}</Reveal>
      </div>
      <div className="atm-believe__grid">
        {t.believe.pillars.map((p, i) => (
          <Reveal key={i} delay={120 + i * 110} className="atm-pillar">
            <span className="atm-pillar__n">{p.n}</span>
            <h3 className="atm-pillar__t">{p.t}</h3>
            <p className="atm-pillar__b">{p.b}</p>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

// ---------- PRODUCTS (stacked deck) ----------
function ProductCard({ item }) {
  return (
    <article className={"atm-prod-card" + (item.hero ? " atm-prod-card--hero" : "")}>
      <div className="atm-prod-card__body">
        {item.hero && <span className="atm-prod-card__chip">{item.tag}</span>}
        <span className="atm-prod-card__n">{item.hero ? "01 · Flagship" : item.n}</span>
        <h3 className="atm-prod-card__name">{item.name}</h3>
        <p className="atm-prod-card__kicker">{item.kicker}</p>
        {item.line && <p className="atm-prod-card__line">{item.line}</p>}
        <p className="atm-prod-card__b">{item.body}</p>
        {item.use && <p className="atm-prod-card__use"><span>Use case</span>{item.use}</p>}
        {item.cta && (
          <a
            className="atm-btn atm-btn--primary atm-prod-card__cta"
            href={item.href || "#contact"}
            target={item.href ? "_blank" : undefined}
            rel={item.href ? "noopener noreferrer" : undefined}
          >
            {item.cta} {item.href ? "↗" : "→"}
          </a>
        )}
      </div>
      <div className="atm-prod-card__visual">
        <img src={res(item.img)} alt={item.name} loading="lazy" />
      </div>
    </article>
  );
}

function Products({ t }) {
  const stackRef = useRef(null);
  const items = useMemo(() => [{ hero: true, ...t.products.featured, n: "01" }, ...t.products.list], [t]);

  // Each card dims/scales as the next one slides over it (--cover 0..1)
  useScrub(() => {
    const stack = stackRef.current;
    if (!stack) return;
    const cards = stack.children;
    for (let i = 0; i < cards.length; i++) {
      const next = cards[i + 1];
      if (!next) { cards[i].style.setProperty("--cover", "0"); continue; }
      const r = cards[i].getBoundingClientRect();
      const nr = next.getBoundingClientRect();
      const dist = window.innerHeight * 0.7;
      cards[i].style.setProperty("--cover", clamp01(1 - (nr.top - r.top) / dist).toFixed(4));
    }
  });

  return (
    <section className="atm-section atm-products" id="products">
      <div className="atm-chapter-head">
        <Reveal as="p" className="atm-eyebrow">{t.products.eyebrow}</Reveal>
        <Reveal as="h2" delay={80} className="atm-section__h2">
          {t.products.title.split("\n").map((l, i) => <span key={i}>{l}</span>)}
        </Reveal>
        <Reveal as="p" delay={140} className="atm-chapter-sub">{t.products.intro}</Reveal>
      </div>

      <div className="atm-stack" ref={stackRef}>
        {items.map((it, i) => (
          <div key={i} className="atm-stack__item">
            <ProductCard item={it} />
          </div>
        ))}
      </div>

      {t.products.also && (
        <Reveal className="atm-also">
          <span className="atm-eyebrow">{t.products.also.label}</span>
          <h3 className="atm-also__t">{t.products.also.title}</h3>
          <ul className="atm-also__list">
            {t.products.also.services.map(([n, b], i) => (
              <li key={i} className="atm-also__item">
                <span className="atm-also__n">{String(i + 1).padStart(2, "0")}</span>
                <span className="atm-also__name">{n}</span>
                <span className="atm-also__b">{b}</span>
              </li>
            ))}
          </ul>
          <p className="atm-also__note">{t.products.also.note}</p>
        </Reveal>
      )}
    </section>
  );
}

// ---------- APPROACH (steps connected by a drawing line) ----------
function Approach({ t }) {
  const trackRef = useRef(null);
  useScrub(() => {
    const el = trackRef.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const vh = window.innerHeight;
    const raw = (vh - r.top) / (vh * 0.75);
    el.style.setProperty("--p", clamp01(raw).toFixed(4));
  });
  return (
    <section className="atm-section atm-approach" id="approach">
      <div className="atm-chapter-head">
        <Reveal as="p" className="atm-eyebrow">{t.approach.eyebrow}</Reveal>
        <Reveal as="h2" delay={80} className="atm-section__h2">
          {t.approach.title.split("\n").map((l, i) => <span key={i}>{l}</span>)}
        </Reveal>
      </div>
      <div className="atm-approach__track" ref={trackRef}>
        <span className="atm-approach__line" aria-hidden="true"></span>
        <div className="atm-approach__grid">
          {t.approach.cols.map((c, i) => (
            <div key={i} className="atm-approach__col" style={{ "--i": i }}>
              <span className="atm-approach__n">{String(i + 1).padStart(2, "0")}</span>
              <h3 className="atm-approach__t">{c.t}</h3>
              <p className="atm-approach__b">{c.b}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ---------- CONTACT ----------
function Contact({ t }) {
  return (
    <section className="atm-section atm-contact" id="contact">
      <div className="atm-chapter-head">
        <Reveal as="p" className="atm-eyebrow">{t.contact.eyebrow}</Reveal>
        <Reveal as="h2" delay={80} className="atm-section__h2">
          {t.contact.title.split("\n").map((l, i) => <span key={i}>{l}</span>)}
        </Reveal>
        <Reveal as="p" delay={140} className="atm-contact__body">{t.contact.body}</Reveal>
      </div>

      <Reveal delay={180}>
        <a href={"mailto:" + t.contact.email} className="atm-contact__mail">
          <span className="atm-contact__mail-label">{t.contact.email_label}</span>
          <span className="atm-contact__mail-addr">{t.contact.email}</span>
          <span className="atm-contact__mail-arrow" aria-hidden="true">↗</span>
        </a>
      </Reveal>

      <div className="atm-contact__info">
        <Reveal delay={220} className="atm-contact__cell">
          <span className="atm-contact__k">{t.contact.company_label}</span>
          <span className="atm-contact__v atm-contact__v--strong">{t.contact.company}</span>
        </Reveal>
        <Reveal delay={280} className="atm-contact__cell">
          <span className="atm-contact__k">{t.contact.office[0]}</span>
          <span className="atm-contact__v">{t.contact.office[1]}</span>
        </Reveal>
        <Reveal delay={340} className="atm-contact__cell">
          <span className="atm-contact__k">{t.contact.socials_label}</span>
          <div className="atm-contact__socials">
            {t.contact.socials.map((s) => (
              <a key={s} href="#" className="atm-social">{s} →</a>
            ))}
          </div>
        </Reveal>
      </div>
    </section>
  );
}

// ---------- FOOTER ----------
function Footer({ t }) {
  return (
    <footer className="atm-footer">
      <div className="atm-footer__top">
        <div className="atm-footer__brand">
          <span className="atm-footer__mark">a touch moment</span>
          <span className="atm-footer__tag">{t.footer.tag}</span>
        </div>
        <ul className="atm-footer__links">
          {t.footer.links.map((l) => <li key={l}><a href="#">{l}</a></li>)}
        </ul>
      </div>
      <div className="atm-footer__bottom">
        <span className="atm-footer__legal">{t.footer.legal}</span>
        <span className="atm-footer__big" aria-hidden="true">a · touch · moment</span>
      </div>
    </footer>
  );
}

Object.assign(window, { Hero, Manifesto, About, Believe, Products, Approach, Contact, Footer, GlobalProgress });
