// OH Community — Auth context + thin global state.
// Wraps the app; provides session, profile, and sign-in/out helpers.
// Per-screen data (posts, journal) is fetched in each screen via SB.* helpers.

const AppCtx = React.createContext(null);

const AppProvider = ({ children }) => {
  const [session, setSession] = React.useState(null);
  const [profile, setProfile] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [signInOpen, setSignInOpen] = React.useState(false);
  const [search, setSearch] = React.useState('');                 // global search query
  const [bellOpen, setBellOpen] = React.useState(false);          // notifications dropdown

  // Admin "View as" override — Phase 1 of the Recovery/Performance fork.
  // Admins can preview the experience for either path without changing
  // their own profile. Stored in sessionStorage so it survives nav but
  // not browser restarts.
  //   null  = no override (use real profile.smell_path)
  //   'recovery' | 'performance' | 'both' = pretend my path is this
  const [viewAsPath, _setViewAsPath] = React.useState(() => {
    try { return sessionStorage.getItem('ovio-view-as-path') || null; } catch { return null; }
  });
  const setViewAsPath = React.useCallback((v) => {
    try {
      if (v) sessionStorage.setItem('ovio-view-as-path', v);
      else sessionStorage.removeItem('ovio-view-as-path');
    } catch {}
    _setViewAsPath(v);
    SB.logEvent('admin_view_as_change', { path: v });
  }, []);

  // Load session on mount + subscribe to auth changes
  React.useEffect(() => {
    let mounted = true;
    SB.getSession().then(s => {
      if (!mounted) return;
      setSession(s);
      setLoading(false);
    });
    const { data: { subscription } } = SB.client.auth.onAuthStateChange((_e, s) => {
      setSession(s);
    });
    return () => { mounted = false; subscription.unsubscribe(); };
  }, []);

  // Load profile when session changes
  React.useEffect(() => {
    if (!session?.user) { setProfile(null); return; }
    SB.getProfile(session.user.id).then(p => setProfile(p));
  }, [session?.user?.id]);

  // After anon-onboarding-then-signin: restore stashed selections to profile.
  // The Onboarding component writes to localStorage when an anon user
  // tries to finish; on return from magic-link we apply it once.
  React.useEffect(() => {
    if (!session?.user?.id) return;
    let stash;
    try { stash = JSON.parse(localStorage.getItem('ovio-onboarding') || 'null'); } catch {}
    if (!stash) return;
    const patch = {};
    if (stash.name)           patch.name = stash.name.trim() || null;
    if (Array.isArray(stash.goals))         patch.goals = stash.goals;
    if (Array.isArray(stash.symptomTypes))  patch.symptom_types = stash.symptomTypes;
    if (Array.isArray(stash.symptom_types)) patch.symptom_types = stash.symptom_types;
    if (typeof stash.experience === 'number') patch.experience = stash.experience;
    if (stash.onsetPeriod)    patch.onset_period = stash.onsetPeriod;
    if (stash.pathway_slug)   patch.pathway_slug = stash.pathway_slug;
    if (stash.smell_path)     patch.smell_path = stash.smell_path;
    if (Array.isArray(stash.paths) && stash.paths.length) patch.paths = stash.paths;
    if (typeof stash.is_local_victoria === 'boolean') patch.is_local_victoria = stash.is_local_victoria;
    if (stash.local_region)   patch.local_region = stash.local_region;
    if (Object.keys(patch).length === 0) { localStorage.removeItem('ovio-onboarding'); return; }
    SB.updateProfile(session.user.id, patch).then(({ data }) => {
      if (data) setProfile(data);
      localStorage.removeItem('ovio-onboarding');
      SB.logEvent('onboarding_restored_after_signin', { fields: Object.keys(patch) });
    });
  }, [session?.user?.id]);

  // Page view event on first load
  React.useEffect(() => {
    SB.logEvent("session_start", { url: window.location.href });
  }, []);

  const signIn = React.useCallback(() => setSignInOpen(true), []);
  const signOut = React.useCallback(async () => {
    await SB.signOut();
    SB.logEvent("sign_out");
  }, []);

  // Convenience: who is "me" right now (real profile or fall back to MOCK.me).
  const me = profile || {
    id: null,
    name: MOCK.me.name,
    role: MOCK.me.role,
    avatar_seed: 0,
    streak: MOCK.me.streak,
    xp: MOCK.me.xp,
    xp_next: MOCK.me.xpNext,
    level_label: MOCK.me.level,
  };

  // Effective path the rest of the app should consult for forked rendering.
  // Admins get their View-As override if set; everyone else uses their own
  // profile.smell_path. Null means "not yet chosen" → fallback to 'both'.
  const isAdmin = profile?.account_type === 'admin';
  const effectivePath = (isAdmin && viewAsPath)
    ? viewAsPath
    : (profile?.smell_path || 'both');

  const value = {
    session,
    profile,
    me,
    isAuthed: !!session?.user,
    isAdmin,
    loading,
    signIn,
    signOut,
    signInOpen,
    setSignInOpen,
    search,
    setSearch,
    bellOpen,
    setBellOpen,
    viewAsPath,         // null | 'recovery' | 'performance' | 'both' (admin-set)
    setViewAsPath,
    effectivePath,      // what render code should consult
    refreshProfile: async () => {
      if (!session?.user) return;
      const p = await SB.getProfile(session.user.id);
      setProfile(p);
    },
  };

  return <AppCtx.Provider value={value}>{children}</AppCtx.Provider>;
};

const useApp = () => {
  const ctx = React.useContext(AppCtx);
  if (!ctx) throw new Error("useApp must be used inside <AppProvider>");
  return ctx;
};

window.AppProvider = AppProvider;
window.useApp = useApp;
