/* Aifit — SpaceX-style genre showcase: full-bleed panels, one statement each.
   Exposes window.GenreShowcase */
(function () {
  const Icon = window.Icon;

  const GENRES = [
    {
      key: "technology", en: "Aifit Technology",
      title: "終活は、迷惑をかけずに旅立つ理想の自分への最高の投資。心の資産形成。",
      brand: "やすらぎ共済会ロードマップ",
      sub: "ご入会は、葬儀費用の割引だけではありません。死後の“面倒”からご自身とご家族を守る「配慮という投資」— それはやがて、予想もつかない“資産”となって還っていきます。",
      href: "technology.html", photo: "img/medical/promise_pic_03.webp", slot: "ph-g-technology", video: "video/tech.mp4", vposter: "img/genre-poster-tech.webp",
    },
    {
      key: "funeral", en: "Funeral & Family",
      title: "大切な人を、最良のかたちで見送る。",
      sub: "直葬8.9万円〜から一般葬まで、選べる13プラン。東広島ご依頼件数 10年連続第1位。",
      href: "plan.html", photo: "img/plan/family/lead_pic.webp", slot: "ph-g-funeral",
    },
    {
      key: "shukatsu", en: "Life Design Salon",
      title: "はじめて不安になった夜を支える。",
      sub: "終活相談ならアイフィット — 遺影撮影・エンディングノート講習・生前整理のご相談。", 
      href: "aifit.html", photo: "img/kyosaikai/img_entry.webp", slot: "ph-g-shukatsu", video: "video/shukatsu.mp4", vposter: "img/genre-poster-shukatsu.webp",
    },
    {
      key: "pet", en: "Pet Ceremony",
      title: "ペットも家族、心を込めて見送る。",
      brand: "アイフィットペット霊園",
      sub: "西条中心部で、ペットの火葬から納骨・永代供養まで。",
      href: "pet.html", photo: "img/pet/explanation_pic01.webp", slot: "ph-g-pet", video: "video/pet-light.mp4", vposter: "img/genre-poster-pet.webp",
    },
    {
      key: "member", en: "Membership",
      title: "一生もののお守り、やすらぎ共済会。",
      brand: "さいきやすらぎ共済会",
      sub: (<React.Fragment>入会金1万円だけでご家族全員割引。当社では面倒な積み立てが本当に不要！！！葬儀費用は最大<b className="gpanel-num">35</b>％OFF！！！</React.Fragment>),
      href: "kyosaikai.html", photo: "img/hall-yasuragi.webp", slot: "ph-g-member", video: "video/kyosaikai.mp4", vposter: "img/genre-poster-member.webp",
    },
    {
      key: "corporate", en: "Corporate & Large-scale",
      title: "1000名規模のご葬儀も。",
      sub: "社葬・合同葬・お別れの会。会場手配から進行・運営まで一括代行。",
      href: "plan-group.html", photo: "img/group/lead_pic.webp", slot: "ph-g-corporate",
    },
    {
      key: "after", en: "After Support",
      title: "葬儀のあとの手続きまで、迷わせない。",
      sub: "香典返し・法事・相続・空き家・遺品整理 — 司法書士初回無料、ワンストップでサポート。",
      href: "after.html", photo: "img/aifit/img_service_10.webp", slot: "ph-g-after", video: "video/kataduke.mp4", vposter: "img/genre-poster-after.webp",
    },
    {
      key: "ai", en: "AI Support — 24 / 365",
      title: "24時間、いつでも、そばに。",
      sub: "Aifitチャット — 自社1万件以上の事象を記憶した専属AIが、登録不要・無料で即答します。",
      href: "https://saiki-sousai.com/chat/", photo: "img/medical/promise_pic_01.webp", slot: "ph-g-ai",
      cta: "Aifitチャットを開く", chips: ["登録不要", "無料", "匿名OK", "24時間365日"],
    },
  ];

  // iOS Safari: React doesn't render the `muted` attribute, which blocks
  // autoplay. Force-mute + play() on mount, retry when data arrives, when
  // the panel scrolls into view, and on any tap.
  function tryPlay(el) {
    if (!el || !el.paused) return;
    el.muted = true;
    const p = el.play();
    if (p && p.catch) p.catch(function () {});
  }
  // Skip video downloads only when they'd be wasted bandwidth: data-saver
  // mode or 2G connections get the (50x smaller) poster photo instead.
  // NOTE: do NOT gate on prefers-reduced-motion — iPhones with 「視差効果を
  // 減らす」 enabled would silently lose every background video.
  const NOVIDEO = (function () {
    try {
      const c = navigator.connection;
      if (c && (c.saveData || /(^|-)2g$/.test(c.effectiveType || ""))) return true;
    } catch (e) {}
    return false;
  })();

  function loadVid(el) {
    if (NOVIDEO) return Promise.resolve();
    if (!el || !el.dataset.src || el.dataset.loaded) return Promise.resolve();
    el.dataset.loaded = "1";
    // iOS Safari needs HTTP range support to stream <video src>; the preview
    // server may not provide it, so fetch the whole file and play as a blob.
    return fetch(el.dataset.src)
      .then(function (r) { if (!r.ok) throw new Error(r.status); return r.blob(); })
      .then(function (b) { el.src = URL.createObjectURL(b); tryPlay(el); })
      .catch(function () { el.src = el.dataset.src; tryPlay(el); });
  }
  function vidMount(el) {
    if (!el) return;
    el.muted = true; el.defaultMuted = true; el.setAttribute("muted", "");
    el.playsInline = true; el.setAttribute("playsinline", "");
    el.preload = "auto";
    el.addEventListener("loadeddata", function () { tryPlay(el); });
    el.addEventListener("canplaythrough", function () { tryPlay(el); });
    // The hero loads immediately; genre-panel videos defer until the panel
    // approaches the viewport (see GenreShowcase) so mobile connections
    // aren't saturated by ~40MB of parallel downloads at page load.
    if (!el.classList.contains("gpanel-video") || !("IntersectionObserver" in window)) loadVid(el);
    tryPlay(el);
  }
  window.aifitVidMount = vidMount;
  window.aifitVidLoad = loadVid;

  function PhoneDemo() {
    const { useState, useEffect } = React;
    const SCRIPTS = [
      [
        { who: "ai", text: "ご自身の終活について考えていらっしゃるんですね。とても大切な一歩です！何でもお気軽にどうぞ 😊" },
        { who: "user", text: "葬儀の費用について" },
        { who: "ai", text: "一番気になるところですよね。Aifitは「明朗会計」がモットー。直葬13.5万円〜、家族葬35.8万円〜（会員価格）。追加料金で驚くことはありません。" },
      ],
      [
        { who: "ai", text: "今日は、誰のためのご相談ですか？どんなご相談でも大丈夫ですよ 🤝" },
        { who: "user", text: "親のことで相談したい" },
        { who: "ai", text: "親御さんのことですね。気持ちの整理から費用のことまで、ご一緒に考えましょう。まずはいまの状況をお聞かせください。" },
      ],
    ];
    const [script] = useState(() => {
      let n = 0;
      try {
        n = (parseInt(localStorage.getItem("aifit-gphone-alt") || "0", 10) + 1) % SCRIPTS.length;
        localStorage.setItem("aifit-gphone-alt", String(n));
      } catch (e) {}
      return SCRIPTS[n];
    });
    const [msgs, setMsgs] = useState([]);
    const [typing, setTyping] = useState(false);
    useEffect(() => {
      let alive = true;
      const timers = [];
      const wait = (ms) => new Promise((r) => { timers.push(setTimeout(r, ms)); });
      (async () => {
        await wait(900);
        while (alive) {
          setMsgs([]);
          for (const m of script) {
            if (!alive) return;
            if (m.who === "ai") { setTyping(true); await wait(1200); setTyping(false); }
            else { await wait(700); }
            for (let i = 1; i <= m.text.length; i++) {
              if (!alive) return;
              const part = m.text.slice(0, i);
              setMsgs((prev) => {
                const next = prev.slice();
                if (next.length && next[next.length - 1].who === m.who && !next[next.length - 1].done) {
                  next[next.length - 1] = { who: m.who, text: part };
                } else { next.push({ who: m.who, text: part }); }
                return next;
              });
              await wait(m.who === "user" ? 70 : 34);
            }
            setMsgs((prev) => {
              const next = prev.slice();
              next[next.length - 1] = { who: m.who, text: m.text, done: true };
              return next;
            });
            await wait(700);
          }
          await wait(4200);
        }
      })();
      return () => { alive = false; timers.forEach(clearTimeout); };
    }, [script]);
    return (
      <div className="gphone" aria-hidden="true">
        <span className="gphone-notch"></span>
        <div className="gphone-screen">
          <div className="gphone-head">
            <span className="gphone-ava">Ai</span>
            <span className="gphone-who"><b>Aifitチャット</b><small><i></i>24時間対応中</small></span>
          </div>
          <div className="gphone-body">
            {msgs.map((m, i) => (
              <span key={i} className={"bub bub--" + m.who}>{m.text}</span>
            ))}
            {typing && <span className="bub bub--ai bub--typing"><i></i><i></i><i></i></span>}
          </div>
          <div className="gphone-input"><span>メッセージを入力…</span><b>↑</b></div>
        </div>
      </div>
    );
  }

  function GenreShowcase() {
    React.useEffect(() => {
      const all = () => Array.prototype.slice.call(document.querySelectorAll("video.gpanel-video, video.hero-video"));
      const kick = () => { all().forEach((v) => { loadVid(v); tryPlay(v); }); };
      window.addEventListener("touchend", kick, { passive: true });
      window.addEventListener("click", kick, { passive: true });
      const io = ("IntersectionObserver" in window)
        ? new IntersectionObserver((es) => {
            es.forEach((e) => { if (e.isIntersecting) { loadVid(e.target); tryPlay(e.target); } else if (!e.target.paused) e.target.pause(); });
          }, { threshold: 0.15 })
        : null;
      if (io) all().forEach((v) => io.observe(v));
      // start loading a panel video well before it scrolls into view
      const ioLoad = ("IntersectionObserver" in window)
        ? new IntersectionObserver((es) => {
            es.forEach((e) => { if (e.isIntersecting) { loadVid(e.target); ioLoad.unobserve(e.target); } });
          }, { rootMargin: "150% 0px" })
        : null;
      if (ioLoad) all().forEach((v) => ioLoad.observe(v));
      // idle prefetch: after the page settles, fetch any remaining videos one
      // at a time so they're ready before the user reaches them.
      const idleTimer = setTimeout(() => {
        all().reduce((p, v) => p.then(() => loadVid(v)), Promise.resolve());
      }, 2500);
      return () => {
        window.removeEventListener("touchend", kick);
        window.removeEventListener("click", kick);
        if (io) io.disconnect();
        if (ioLoad) ioLoad.disconnect();
        clearTimeout(idleTimer);
      };
    }, []);
    return (
      <section className="genres" aria-label="Aifitのサービス">
        {GENRES.map((g) => {
          const ext = /^https?:/.test(g.href);
          return (
            <a key={g.key} className={"gpanel gpanel--" + g.key + (g.photo ? "" : " gpanel--plain")}
               href={g.href} data-screen-label={"ジャンル：" + g.en}
               target={ext ? "_blank" : undefined} rel={ext ? "noopener" : undefined}>
              {g.photo && (
                <image-slot id={g.slot} src={g.photo} shape="rect" placeholder={g.en + "の写真"}
                  style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}></image-slot>
              )}
              {g.video && (
                <video className="gpanel-video" data-src={g.video} poster={g.vposter || g.photo} ref={vidMount} autoPlay muted loop playsInline aria-hidden="true"></video>
              )}
              <span className="gpanel-scrim" aria-hidden="true"></span>
              {g.inset && (
                <span className="gpanel-inset" aria-hidden="true"><img src={g.inset} alt="" loading="lazy" /></span>
              )}
              {g.key === "ai" && <PhoneDemo />}
              <div className="wrap gpanel-wrap">
                <div className="gpanel-tx reveal">
                  <span className="gpanel-kicker">{g.en}</span>
                  <h3 className="gpanel-title">{g.title}</h3>
                  {g.brand && <span className="gpanel-brand">{g.brand}</span>}
                  <p className="gpanel-sub">{g.sub}</p>
                  {g.chips && (
                    <span className="gpanel-chips">{g.chips.map((c, i) => (<span key={i} className="gpanel-chip">{c}</span>))}</span>
                  )}
                  <span className="gpanel-link">{g.cta || "詳しく見る"}<Icon name="arrow" strokeWidth={1.8} /></span>
                </div>
              </div>
            </a>
          );
        })}
      </section>
    );
  }

  window.GenreShowcase = GenreShowcase;
})();
