/* ───────────────────────────────────────────────
   Happy Guts — installable web app (PWA)
   • service-worker registration (built/deployed copy only — see scripts/build.mjs)
   • install-status detection: running installed? can the browser prompt? which platform?
   • install nudges, on every open until installed: InstallGate (full screen, phones),
     InstallBanner on Home, InstallCard in Settings
   Exposed: useInstall, promptInstall, InstallGate, InstallBanner, InstallCard, InstallHelp,
            UpdateToast, shouldShowInstallGate, markInstallGateSeen
   ─────────────────────────────────────────────── */

/* ── service worker ── */
(function registerServiceWorker() {
  // dist/index.html sets window.HG_BUILD; the zero-build dev page doesn't, so dev never caches.
  if (!window.HG_BUILD || !('serviceWorker' in navigator)) return;
  const register = () => navigator.serviceWorker.register('sw.js')
    .catch(err => console.warn('[Happy Guts] Service worker registration failed:', err));
  if (document.readyState === 'complete') register();
  else window.addEventListener('load', register);
})();

/* ── install-status store (module singleton, so events fired before React mounts aren't lost) ── */
const pwaStore = (() => {
  const ua = navigator.userAgent || '';
  const ios = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
  const android = /Android/i.test(ua);
  // In-app browsers (Instagram, Facebook, TikTok, LinkedIn, Google app…) can't add to the home screen.
  const inApp = /FBAN|FBAV|FB_IAB|Instagram|Line\/|LinkedInApp|Twitter|Snapchat|TikTok|musical_ly|Bytedance|MicroMessenger|GSA\//i.test(ua)
    || (android && /; wv\)/.test(ua));
  const iosBrowser = !ios ? null : /CriOS/.test(ua) ? 'chrome' : /FxiOS/.test(ua) ? 'firefox' : /EdgiOS/.test(ua) ? 'edge' : 'safari';
  const platform = ios ? 'ios' : android ? 'android' : 'desktop';

  let promptEvent = window.__hgInstallPrompt || null;   // captured early by an inline script in index.html
  let justInstalled = !!window.__hgAppInstalled;
  const listeners = new Set();
  const emit = () => listeners.forEach(fn => fn());

  const mq = (q) => (window.matchMedia ? window.matchMedia(q) : { matches: false });
  const standaloneMQ = mq('(display-mode: standalone)');
  const isStandalone = () => standaloneMQ.matches || mq('(display-mode: fullscreen)').matches || window.navigator.standalone === true;

  const markInstalled = () => { try { localStorage.setItem('hg_installed', JSON.stringify(Date.now())); } catch {} };
  const knownInstalled = () => { try { return !!localStorage.getItem('hg_installed'); } catch { return false; } };
  if (isStandalone()) markInstalled();   // Android shares storage between browser + installed app, so a later browser visit knows

  // A new deploy's service worker takes over straight away (skipWaiting); offer a reload so the
  // page picks up the new app shell. Skipped on the very first install (no previous controller).
  let updateReady = false;
  if (navigator.serviceWorker) {
    const hadController = !!navigator.serviceWorker.controller;
    navigator.serviceWorker.addEventListener('controllerchange', () => {
      if (hadController) updateReady = true;
      emit();
    });
  }

  window.addEventListener('beforeinstallprompt', (e) => { e.preventDefault(); promptEvent = e; emit(); });
  window.addEventListener('appinstalled', () => { justInstalled = true; promptEvent = null; markInstalled(); emit(); });
  if (standaloneMQ.addEventListener) standaloneMQ.addEventListener('change', emit);

  return {
    subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn); },
    snapshot() {
      const standalone = isStandalone();
      return {
        standalone,                       // running as the installed app right now
        platform, iosBrowser, inApp,
        mobile: platform !== 'desktop',
        canPrompt: !!promptEvent,         // Chrome/Edge/Samsung can show their own install dialog
        justInstalled,                    // installed during this visit
        knownInstalled: knownInstalled(), // installed earlier (only detectable where storage is shared, e.g. Android)
        offlineReady: !!(navigator.serviceWorker && navigator.serviceWorker.controller),
        updateReady,
      };
    },
    async prompt() {
      if (!promptEvent) return 'unavailable';
      const e = promptEvent; promptEvent = null; emit();
      e.prompt();
      const { outcome } = await e.userChoice;      // 'accepted' | 'dismissed'
      if (outcome === 'accepted') { justInstalled = true; markInstalled(); }
      emit();
      return outcome;
    },
  };
})();

// "Installed" as far as this page can tell. iPhone/iPad give a browser tab no way to know whether
// the home-screen app exists (separate storage, no API), so there it's only true inside the app.
function isInstalled(s) {
  return s.standalone || s.justInstalled || (s.knownInstalled && !s.canPrompt);
}

// Dismissals last for this open only (sessionStorage = this tab until it's closed), so the
// nudge comes back every time the site is opened in a browser, but not on a reload mid-visit.
const session = {
  has(k) { try { return !!sessionStorage.getItem(k); } catch { return false; } },
  set(k) { try { sessionStorage.setItem(k, '1'); } catch {} },
};

function useInstall() {
  const [, force] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => pwaStore.subscribe(force), []);
  return pwaStore.snapshot();
}
const promptInstall = () => pwaStore.prompt();

/* ── small pieces ── */
function Step({ n, children }) {
  return (
    <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
      <span style={{ width: 26, height: 26, borderRadius: 99, background: 'var(--spark-tint)', color: 'var(--spark-ink)',
        fontWeight: 800, fontSize: 13.5, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{n}</span>
      <div style={{ fontSize: 14.5, lineHeight: 1.45, color: 'var(--ink-2)', paddingTop: 2 }}>{children}</div>
    </div>
  );
}
const Glyph = ({ name }) => (
  <span style={{ display: 'inline-flex', verticalAlign: '-5px', margin: '0 2px' }}>
    <window.Icon name={name} size={20} color="var(--ink)" />
  </span>
);

function CopyLink() {
  const [copied, setCopied] = React.useState(false);
  const copy = async () => {
    try { await navigator.clipboard.writeText(location.href); setCopied(true); setTimeout(() => setCopied(false), 2000); }
    catch { window.prompt('Copy this link:', location.href); }
  };
  return (
    <button className="btn btn-ghost" onClick={copy} style={{ padding: '11px 16px', fontSize: 14.5 }}>
      <window.Icon name={copied ? 'check' : 'copy'} size={18} /> {copied ? 'Link copied' : 'Copy link'}
    </button>
  );
}

/* ── platform-specific "how to install" — shared by gate, banner sheet and settings ── */
function InstallHelp({ s }) {
  if (s.standalone) {
    return <p style={{ fontSize: 14.5, color: 'var(--ink-2)' }}>You're using the installed app. 🎉</p>;
  }
  if (s.justInstalled || (s.knownInstalled && !s.canPrompt)) {
    return (
      <div style={{ background: 'var(--safe-tint)', borderRadius: 16, padding: 16, display: 'flex', gap: 12 }}>
        <window.Icon name="check" size={22} color="var(--safe-ink)" />
        <div style={{ fontSize: 14.5, color: 'var(--safe-ink)', lineHeight: 1.45 }}>
          <b>Happy Guts is installed.</b> Open it from your home screen (or app list) for the full-screen, offline experience.
        </div>
      </div>
    );
  }
  if (s.inApp) {
    const where = s.platform === 'ios' ? 'Safari' : 'Chrome';
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <p style={{ fontSize: 14.5, color: 'var(--ink-2)', lineHeight: 1.45 }}>
          You've opened this inside another app, which can't install it. Open the page in <b>{where}</b> instead —
          use the <Glyph name="more" /> menu and choose <b>Open in {s.platform === 'ios' ? 'browser' : where}</b>, or copy the link.
        </p>
        <div><CopyLink /></div>
      </div>
    );
  }
  if (s.canPrompt) {
    return (
      <button className="btn btn-spark btn-block" onClick={() => promptInstall()}>
        <window.Icon name="download" size={20} color="#fff" /> Install app
      </button>
    );
  }
  if (s.platform === 'ios') {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <Step n={1}>Tap <b>Share</b> <Glyph name="share" />
          {s.iosBrowser === 'safari'
            ? <> in Safari's toolbar. Don't see it? Tap <Glyph name="moreH" /> first.</>
            : <> next to the address bar.</>}</Step>
        <Step n={2}>Scroll down and tap <b>Add to Home Screen</b> <Glyph name="addBox" /></Step>
        <Step n={3}>Tap <b>Add</b>, then open <b>Happy Guts</b> from your Home Screen.</Step>
      </div>
    );
  }
  if (s.platform === 'android') {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <Step n={1}>Open your browser menu <Glyph name="more" /></Step>
        <Step n={2}>Tap <b>Install app</b> or <b>Add to Home screen</b></Step>
        <Step n={3}>Open <b>Happy Guts</b> from your home screen.</Step>
      </div>
    );
  }
  return (
    <p style={{ fontSize: 14, color: 'var(--ink-2)', lineHeight: 1.45 }}>
      In Chrome or Edge, use the install icon <Glyph name="download" /> in the address bar. In Safari on a Mac, choose
      <b> File → Add to Dock</b>.
    </p>
  );
}

const BENEFITS = [
  ['scan', 'Opens full screen, straight to the scanner'],
  ['leaf', 'Works offline — your food guide is always to hand'],
  ['check', 'Keeps your profile and lists safely on this phone'],
];

/* ── shown on phones each time the site is opened in a browser, until installed ── */
function InstallGate({ onContinue }) {
  const s = useInstall();
  return (
    <div className="app-root scroll" style={{ height: '100%', background: 'var(--bg)' }}>
      <div style={{ maxWidth: 460, margin: '0 auto', padding: 'calc(28px + env(safe-area-inset-top, 0px)) 22px calc(28px + env(safe-area-inset-bottom, 0px))',
        display: 'flex', flexDirection: 'column', gap: 22, minHeight: '100%' }}>
        <window.BrandMark size={40} />
        <div>
          <h1 style={{ fontSize: 31 }}>Install Happy Guts</h1>
          <p style={{ fontSize: 15.5, color: 'var(--ink-2)', marginTop: 8, lineHeight: 1.45 }}>
            Add it to your home screen for the best experience.
          </p>
        </div>
        <div className="card" style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 13 }}>
          {BENEFITS.map(([icon, text]) => (
            <div key={text} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <span style={{ width: 34, height: 34, borderRadius: 11, background: 'var(--spark-tint)', flexShrink: 0,
                display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <window.Icon name={icon} size={19} color="var(--spark-ink)" />
              </span>
              <span style={{ fontSize: 14.5, fontWeight: 600, color: 'var(--ink)' }}>{text}</span>
            </div>
          ))}
        </div>
        <div className="card" style={{ padding: 18 }}>
          <div className="eyebrow" style={{ marginBottom: 12 }}>How to install</div>
          <InstallHelp s={s} />
        </div>
        {s.platform === 'ios' && !s.justInstalled && (
          <p style={{ fontSize: 13, color: 'var(--ink-3)', lineHeight: 1.45, marginTop: -8 }}>
            Install first, then set up inside the app — on iPhone the installed app keeps its own copy of your
            profile, separate from Safari.
          </p>
        )}
        <div style={{ marginTop: 'auto' }}>
          <button className="btn btn-ghost btn-block" onClick={onContinue} style={{ fontSize: 15.5 }}>
            Continue in browser
          </button>
        </div>
      </div>
    </div>
  );
}

/* ── reminder on Home — every open until installed; ✕ hides it for this open only ── */
const BANNER_KEY = 'hg_install_banner_dismissed';
function InstallBanner({ style }) {
  const s = useInstall();
  const [open, setOpen] = React.useState(false);
  const [hidden, setHidden] = React.useState(() => session.has(BANNER_KEY));
  if (isInstalled(s) || hidden || (!s.mobile && !s.canPrompt)) return null;
  const snooze = () => { session.set(BANNER_KEY); setHidden(true); };
  const install = async () => { if (s.canPrompt) await promptInstall(); else setOpen(true); };
  return (
    <React.Fragment>
      <div style={{ background: 'var(--card)', borderRadius: 18, boxShadow: 'var(--shadow-1)',
        padding: '11px 10px 11px 14px', display: 'flex', alignItems: 'center', gap: 11, ...style }}>
        <window.Icon name="download" size={22} color="var(--spark)" />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 700, fontSize: 14.5 }}>Install Happy Guts</div>
          <div style={{ fontSize: 12.5, color: 'var(--ink-3)' }}>Full screen, offline, one tap away</div>
        </div>
        <button className="btn btn-spark" onClick={install} style={{ padding: '9px 14px', fontSize: 14 }}>Install</button>
        <button className="btn" onClick={snooze} aria-label="Not now" style={{ background: 'transparent', padding: 4 }}>
          <window.Icon name="x" size={18} color="var(--ink-3)" />
        </button>
      </div>
      <window.Sheet open={open} onClose={() => setOpen(false)} title="Install Happy Guts">
        <InstallHelp s={s} />
      </window.Sheet>
    </React.Fragment>
  );
}

/* ── Settings → App ── */
function InstallCard() {
  const s = useInstall();
  const [open, setOpen] = React.useState(false);
  const status = s.standalone ? 'Installed — running as an app' : s.justInstalled || s.knownInstalled ? 'Installed — open it from your home screen' : 'Running in your browser';
  return (
    <div className="card" style={{ overflow: 'hidden' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', borderBottom: '1px solid var(--line)' }}>
        <window.Icon name={s.standalone ? 'check' : 'download'} size={20} color={s.standalone ? 'var(--safe)' : 'var(--ink-3)'} />
        <div style={{ flex: 1 }}>
          <div style={{ fontWeight: 700, fontSize: 15 }}>{status}</div>
          <div style={{ fontSize: 12.5, color: 'var(--ink-3)', marginTop: 1 }}>
            {s.offlineReady ? 'Available offline' : window.HG_BUILD ? 'Preparing offline copy…' : 'Offline mode is only in the built app'}
          </div>
        </div>
        {!s.standalone && (
          <button className="btn btn-spark" onClick={() => (s.canPrompt ? promptInstall() : setOpen(true))}
            style={{ padding: '9px 14px', fontSize: 14 }}>Install</button>
        )}
      </div>
      <div style={{ padding: '10px 16px', fontSize: 11.5, color: 'var(--ink-3)' }} className="mono">
        {window.HG_BUILD ? `build ${window.HG_BUILD.version}` : 'dev (unbuilt)'}
      </div>
      <window.Sheet open={open} onClose={() => setOpen(false)} title="Install Happy Guts">
        <InstallHelp s={s} />
      </window.Sheet>
    </div>
  );
}

/* ── "new version" toast (after a deploy) ── */
function UpdateToast() {
  const s = useInstall();
  const [dismissed, setDismissed] = React.useState(false);
  if (!s.updateReady || dismissed) return null;
  return (
    <div style={{ position: 'absolute', left: 12, right: 12, bottom: 'calc(92px + env(safe-area-inset-bottom, 0px))', zIndex: 90,
      background: 'var(--ink)', color: '#fff', borderRadius: 16, padding: '10px 10px 10px 16px',
      display: 'flex', alignItems: 'center', gap: 10, boxShadow: 'var(--shadow-pop)', animation: 'hgFade .2s ease' }}>
      <span style={{ flex: 1, fontSize: 14, fontWeight: 600 }}>A new version of Happy Guts is ready.</span>
      <button className="btn btn-spark" onClick={() => location.reload()} style={{ padding: '8px 14px', fontSize: 14 }}>Reload</button>
      <button className="btn" onClick={() => setDismissed(true)} aria-label="Dismiss" style={{ background: 'transparent', padding: 4 }}>
        <window.Icon name="x" size={18} color="rgba(255,255,255,.7)" />
      </button>
    </div>
  );
}

/* install page bookkeeping: shown on every open on a phone until the app is installed */
const GATE_KEY = 'hg_install_gate_dismissed';
function shouldShowInstallGate() {
  const s = pwaStore.snapshot();
  if (isInstalled(s) || !s.mobile) return false;
  if (new URLSearchParams(location.search).has('noinstall')) return false;   // escape hatch for testing / links
  return !session.has(GATE_KEY);
}
function markInstallGateSeen() { session.set(GATE_KEY); }

Object.assign(window, { useInstall, promptInstall, InstallGate, InstallBanner, InstallCard, InstallHelp, UpdateToast,
  shouldShowInstallGate, markInstallGateSeen });
