// App controller: real session boot, per-tab navigation stacks, synced store.
(function () {
  const { useState, useEffect, useRef } = React;
  const { TabBar } = window.NLUI;
  const { Welcome } = window.NLAuth;
  const { Home, Live } = window.NLHome;
  const { Watch, SermonDetail, GalleryDetail, Galleries } = window.NLWatch;
  const { Bible, Reader, Highlights } = window.NLBible;
  const { Give } = window.NLGive;
  const { Events, EventDetail, Prayer, Bulletin } = window.NLCommunity;
  const { More, Profile, Notifications, Downloads, Search } = window.NLMore;
  const { Serving } = window.NLServing;
  const D = window.NLData;
  const Api = window.NLApi;

  const SCREENS = {
    home: Home, watch: Watch, bible: Bible, give: Give, more: More,
    sermon: SermonDetail, gallery: GalleryDetail, galleries: Galleries, live: Live,
    reader: Reader, highlights: Highlights,
    events: Events, event: EventDetail, prayer: Prayer, bulletin: Bulletin,
    profile: Profile, notifications: Notifications, downloads: Downloads, search: Search,
    serving: Serving,
  };
  const ROOT = { home: 'home', watch: 'watch', bible: 'bible', give: 'give', more: 'more' };
  const FULLSCREEN = new Set(['live', 'search', 'reader']);

  const KEY = 'nlc_app_v2';
  const seed = {
    notes: {}, highlights: {}, verseNotes: {}, downloads: [],
    progress: {}, lastChapter: 'John 1', prayed: [],
  };

  function loadLocal() {
    try {
      const raw = localStorage.getItem(KEY);
      if (raw) return { ...seed, ...JSON.parse(raw) };
    } catch (e) {}
    return { ...seed };
  }

  function authErrorFromUrl() {
    const p = new URLSearchParams(window.location.search);
    const err = p.get('auth_error');
    if (err) window.history.replaceState({}, '', window.location.pathname);
    return err;
  }

  function App() {
    const [phase, setPhase] = useState('boot');       // boot → welcome → app
    const [authError] = useState(authErrorFromUrl);
    const [st, setSt] = useState(loadLocal);
    const [tab, setTab] = useState('home');
    const [stacks, setStacks] = useState({ home: [], watch: [], bible: [], give: [], more: [] });
    const [dataRev, setDataRev] = useState(0);        // bumped when NLData changes
    const [downloading, setDownloading] = useState({});
    const bump = () => setDataRev(r => r + 1);

    // ---- boot: who am I, and is there a real backend? ----------------------
    useEffect(() => {
      let alive = true;
      (async () => {
        const { mode, user } = await Api.me();
        if (!alive) return;
        D.mode = mode;
        if (mode === 'demo') { setPhase(localStorage.getItem('nlc_demo_authed') ? 'app' : 'welcome'); return; }
        if (!user) { setPhase('welcome'); return; }
        try {
          const b = await Api.bootstrap();
          if (!alive) return;
          D.user = b.user;
          D.sermons = (b.sermons || []).map(D.mapSermon);
          D.live = b.live || { isLive: false };
          D.events = (b.events || []).map(D.mapEvent);
          D.galleries = (b.galleries || []).map(D.mapGallery);
          D.announcements = (b.announcements || []).map(a => ({ tag: a.tag || 'News', theme: a.theme || 'leaf', ...a }));
          D.config = { ...D.config, ...(b.config || {}) };
          setSt(s => ({ ...s, ...(b.state || {}) })); // server state wins
          setPhase('app');
          // Serving loads after first paint — it's a per-user PCO call.
          Api.serving().then(r => { D.serving = r.serving || []; D.servingUnavailable = !!r.unavailable; bump(); }).catch(() => {});
        } catch (e) {
          // Signed in but bootstrap failed (offline?) — run on cached/demo data.
          D.user = user;
          setPhase('app');
        }
      })();
      return () => { alive = false; };
    }, []);

    // ---- persist + sync state ----------------------------------------------
    useEffect(() => {
      try { localStorage.setItem(KEY, JSON.stringify(st)); } catch (e) {}
      if (phase === 'app' && D.mode === 'live') {
        Api.syncState({
          notes: st.notes, highlights: st.highlights, verseNotes: st.verseNotes,
          downloads: st.downloads, progress: st.progress, lastChapter: st.lastChapter, prayed: st.prayed,
        });
      }
    }, [st, phase]);

    // keep sermon progress fresh for the card renderers
    D.sermons.forEach(s => { const p = st.progress[s.id]; s.progress = p ? p.f || 0 : 0; });

    const patch = (p) => setSt(s => ({ ...s, ...(typeof p === 'function' ? p(s) : p) }));

    const store = {
      ...st,
      user: D.user,
      refresh: bump,
      setNote: (id, v) => patch(s => ({ notes: { ...s.notes, [id]: v } })),
      setProgress: (id, seconds, duration) => patch(s => ({
        progress: { ...s.progress, [id]: { t: Math.floor(seconds), f: duration ? Math.min(1, seconds / duration) : 0 } },
      })),
      resumeTime: (id) => (st.progress[id] && st.progress[id].t) || 0,
      isDownloaded: (id) => st.downloads.includes(id),
      downloadState: (id) => downloading[id] || null,
      startDownload: async (s) => {
        if (!s.videoUrl) return;
        setDownloading(d => ({ ...d, [s.id]: 'downloading' }));
        try {
          await Api.downloadSermon(s.videoUrl);
          patch(p => ({ downloads: p.downloads.includes(s.id) ? p.downloads : [...p.downloads, s.id] }));
        } catch (e) {
          alert('Could not save for offline. Check your connection and try again.');
        }
        setDownloading(d => { const n = { ...d }; delete n[s.id]; return n; });
      },
      removeDownload: async (s) => {
        try { await Api.removeDownload(s.videoUrl); } catch (e) {}
        patch(p => ({ downloads: p.downloads.filter(x => x !== s.id) }));
      },
      isPrayed: (id) => st.prayed.includes(id),
      togglePrayed: (id) => patch(s => ({ prayed: s.prayed.includes(id) ? s.prayed.filter(x => x !== id) : [...s.prayed, id] })),
      setHighlight: (ch, n, color) => patch(s => {
        const next = { ...s.highlights, [ch]: { ...(s.highlights[ch] || {}) } };
        if (color) next[ch][n] = color; else delete next[ch][n];
        if (Object.keys(next[ch]).length === 0) delete next[ch];
        return { highlights: next };
      }),
      setVerseNote: (key, v) => patch(s => {
        const next = { ...s.verseNotes };
        if (v && v.trim()) next[key] = v; else delete next[key];
        return { verseNotes: next };
      }),
      setLastChapter: (c) => patch({ lastChapter: c }),
      setServing: (id, status) => {
        D.serving = D.serving.map(a => a.id === id ? { ...a, status } : a);
        bump();
        if (D.mode === 'live') {
          Api.respondServing(id, status === 'confirmed' ? 'accept' : 'decline').then(r => {
            if (!r.ok && r.churchCenterUrl) {
              alert('Planning Center needs you to respond in Church Center for this one — opening it now.');
              window.open(r.churchCenterUrl, '_blank');
            }
          }).catch(() => {});
        }
      },
      signOut: async () => {
        localStorage.removeItem('nlc_demo_authed');
        if (D.mode === 'live') await Api.logout();
        window.location.replace('/');
      },
    };

    const nav = {
      push: (name, params) => setStacks(s => ({ ...s, [tab]: [...s[tab], { name, params: params || {} }] })),
      pop: () => setStacks(s => ({ ...s, [tab]: s[tab].slice(0, -1) })),
      tab: (id) => { setTab(id); setStacks(s => ({ ...s, [id]: [] })); },
    };

    const stack = stacks[tab];
    const current = stack.length ? stack[stack.length - 1] : { name: ROOT[tab], params: {} };
    const dark = phase !== 'app' || current.name === 'live' || current.name === 'sermon';
    useEffect(() => {
      const meta = document.querySelector('meta[name="theme-color"]');
      if (meta) meta.setAttribute('content', dark ? '#051F2E' : '#FBFAF6');
    }, [dark]);

    // ---- phases -------------------------------------------------------------
    if (phase === 'boot') return <Splash />;
    if (phase === 'welcome') {
      return <Welcome error={authError} onContinue={() => {
        if (D.mode === 'demo') { localStorage.setItem('nlc_demo_authed', '1'); setPhase('app'); }
        else Api.login();
      }} />;
    }

    const Comp = SCREENS[current.name] || Home;
    const hideTabs = FULLSCREEN.has(current.name);

    return (
      <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--nl-bg)' }}>
        <div style={{ flex: 1, minHeight: 0, position: 'relative', overflow: 'hidden' }}>
          <Comp key={tab + ':' + stack.length + ':' + current.name + ':' + dataRev}
            nav={nav} store={store} params={current.params} />
        </div>
        {!hideTabs && <TabBar active={tab} onChange={(id) => nav.tab(id)} />}
      </div>
    );
  }

  function Splash() {
    return (
      <div style={{ height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center',
        background: 'linear-gradient(165deg, var(--nl-navy-700) 0%, var(--nl-navy-900) 70%)' }}>
        <img src="assets/logo-reverse.png" alt="New Life Church" style={{ height: 44, opacity: 0.9 }} />
      </div>
    );
  }

  window.NLApp = App;
})();
