// Naviyell — navigation + global app state for the interactive prototype

const NavContext = React.createContext(null);
const StateContext = React.createContext(null);

function useNav() {
  return React.useContext(NavContext);
}
function useAppState() {
  return React.useContext(StateContext);
}

// Screens that have a bottom tab bar (so back from these = no-op or exit)
const TAB_SCREENS = new Set(['home', 'browse', 'messages', 'tracker', 'mypage', 'anchors']);

function NavProvider({ initial = 'splash', children }) {
  const [stack, setStack] = React.useState([initial]);
  const [transition, setTransition] = React.useState(null); // {from, to, dir}

  // ── Global mutable app state (used across screens) ──
  const [appState, setAppState] = React.useState({
    hearing: { 1: null, 2: null, 3: null, 4: null },
    // 30-question diagnosis: { 1: 0|1|2, 2: 0|1|2, ... } (0=Wind 1=Fire 2=Earth)
    diagnosis: {},
    diagQ: 1,
    // Birthday for Born Inner Type
    birthYear: 1985,
    birthMonth: 7,
    birthDay: 15,
    onbSlide: 0,
    hearingStep: 1,
    selectedTicket: null, // ticket id
    selectedAnchor: null,
    selectedSlot: { date: 26, time: '14:00' },
    bookingComplete: false,
    actions: null, // populated from MOCK
    messages: null, // session message log
    auth: { tab: 'login', email: '', password: '', firstName: '', lastName: '' },
    paymentTab: 0,
    cancelDialog: false,
    showAddedToast: false,
    toastMessage: null,
    statusStep: 2, // 0..3 for the stepper
  });

  const patch = React.useCallback((p) => {
    setAppState((s) => ({ ...s, ...(typeof p === 'function' ? p(s) : p) }));
  }, []);

  // ── Supabase session routing ──
  // Track current user in a ref so the event handler can check it synchronously
  // (state updates are async, so `appState.currentUser` would be stale in the closure).
  const currentUserRef = React.useRef(null);

  // When the user reaches 'home' while signed in, mark onboarding complete.
  // Checked by routeForUser so subsequent sign-ins skip onboarding.
  React.useEffect(() => {
    const cur = stack[stack.length - 1];
    if (cur === 'home' && appState.currentUser) {
      localStorage.setItem('naviyell_onb_' + appState.currentUser.id, '1');
    }
  }, [stack, appState.currentUser]);

  React.useEffect(() => {
    if (typeof DB === 'undefined') return;

    const isNewAccount = (user) => Date.now() - new Date(user.created_at).getTime() < 5 * 60 * 1000;

    const routeForUser = (user) => {
      if (user.user_metadata?.onboarding_complete) return 'home';
      if (localStorage.getItem('naviyell_onb_' + user.id)) return 'home';
      return isNewAccount(user) ? 'onboarding' : 'home';
    };

    const applyProfile = (profile, user) => {
      if (!profile) return;
      // Prioritize user metadata (more up-to-date) over profile data
      setAppState((s) => ({
        ...s,
        displayName: 
          user?.user_metadata?.public_username ||
          user?.user_metadata?.full_name ||
          user?.user_metadata?.name ||
          profile.display_name ||
          profile.public_username ||
          s.displayName,
        firstName: profile.first_name || user?.user_metadata?.first_name || s.firstName,
        lastName: profile.last_name || user?.user_metadata?.last_name || s.lastName,
        avatarUrl: profile.avatar_url || s.avatarUrl,
        selfIntro: profile.self_intro || s.selfIntro,
        twitter: profile.twitter || s.twitter,
        instagram: profile.instagram || s.instagram,
        // ✅ Load birthday data from user_metadata FIRST, then fall back to profile
        // This ensures data persists even if profiles table is out of sync
        bornType: user?.user_metadata?.born_type || profile.born_type || s.bornType,
        birthYear: user?.user_metadata?.birth_year || profile.birth_year || s.birthYear,
        birthMonth: user?.user_metadata?.birth_month || profile.birth_month || s.birthMonth,
        birthDay: user?.user_metadata?.birth_day || profile.birth_day || s.birthDay,
      }));
    };

    const {
      data: { subscription },
    } = DB.onAuthStateChange((event, session) => {
      if (event === 'INITIAL_SESSION') {
        if (session) {
          currentUserRef.current = session.user;
          setAppState((s) => ({ ...s, currentUser: session.user }));
          setStack([routeForUser(session.user)]);
          setTransition(null);
          DB.loadProfile().then((profile) => applyProfile(profile, session.user)).catch(() => {});
        }
        // No session — stay on splash, it routes to login naturally
      } else if (event === 'SIGNED_IN' && session) {
        // Only navigate when this is a genuine transition from signed-out.
        // Supabase re-fires SIGNED_IN on tab-focus token refreshes; if the user
        // already has a currentUser (or just signed out), ignore the navigation.
        const wasSignedOut = !currentUserRef.current;
        currentUserRef.current = session.user;
        setAppState((s) => ({ ...s, currentUser: session.user }));
        DB.loadProfile().then((profile) => applyProfile(profile, session.user)).catch(() => {});
        if (wasSignedOut) {
          setStack((prev) => {
            const cur = prev[prev.length - 1];
            if (cur === 'login' || cur === 'splash') return [routeForUser(session.user)];
            return prev;
          });
          setTransition(null);
        }
      } else if (event === 'PASSWORD_RECOVERY') {
        // User clicked the reset-password link in their email.
        // Supabase has already established a recovery session — route straight
        // to the password-reset screen so they can set a new password.
        currentUserRef.current = session?.user ?? currentUserRef.current;
        if (session?.user) setAppState((s) => ({ ...s, currentUser: session.user }));
        setStack(['password-reset']);
        setTransition(null);
      } else if (event === 'SIGNED_OUT') {
        currentUserRef.current = null;
        setAppState((s) => ({ ...s, currentUser: null }));
        setStack(['login']);
        setTransition(null);
      }
    });
    return () => subscription.unsubscribe();
  }, []);

  const current = stack[stack.length - 1];

  const go = React.useCallback(
    (to, opts = {}) => {
      if (to === current) return;
      setTransition({ from: current, to, dir: opts.dir || 'forward' });
      setTimeout(() => {
        setStack((s) => (opts.replace ? [...s.slice(0, -1), to] : [...s, to]));
        setTimeout(() => setTransition(null), 240);
      }, 0);
    },
    [current],
  );

  const back = React.useCallback(
    (fallback) => {
      if (stack.length <= 1) {
        if (fallback && fallback !== current) {
          // graceful fallback: navigate to a sensible parent screen
          setTransition({ from: current, to: fallback, dir: 'back' });
          setTimeout(() => {
            setStack([fallback]);
            setTimeout(() => setTransition(null), 240);
          }, 0);
        }
        return;
      }
      const to = stack[stack.length - 2];
      setTransition({ from: current, to, dir: 'back' });
      setTimeout(() => {
        setStack((s) => s.slice(0, -1));
        setTimeout(() => setTransition(null), 240);
      }, 0);
    },
    [stack, current],
  );

  // Reset to a tab's home (e.g. tab bar tap)
  const tab = React.useCallback(
    (to) => {
      if (to === current) return;
      setTransition({ from: current, to, dir: 'fade' });
      setTimeout(() => {
        setStack([to]);
        setTimeout(() => setTransition(null), 240);
      }, 0);
    },
    [current],
  );

  const navApi = React.useMemo(() => ({ go, back, tab, current, stack, transition }), [go, back, tab, current, stack, transition]);
  const stateApi = React.useMemo(() => ({ state: appState, patch }), [appState, patch]);

  return (
    <NavContext.Provider value={navApi}>
      <StateContext.Provider value={stateApi}>{children}</StateContext.Provider>
    </NavContext.Provider>
  );
}

// ── Screen registry: lazy refs to globals (the screen components) ──
function getScreen(id) {
  const map = {
    splash: () => window.A01Splash,
    onboarding: () => window.A02Onboarding,
    login: () => window.A03Login,
    hearing: () => window.A04Hearing,
    'hearing-transition': () => window.A04Transition,
    birthday: () => window.A04Birthday,
    'type-reveal': () => window.A04TypeReveal,
    'diagnosis-intro': () => window.A04DiagnosisIntro,
    diagnosis: () => window.A05Diagnosis,
    'result-intro': () => window.A05ResultIntro,
    result: () => window.A05Result,
    home: () => window.A06Home,
    browse: () => window.A07Browse,
    'ticket-detail': () => window.A08TicketDetail,
    anchors: () => window.A09AnchorList,
    'anchor-detail': () => window.A09AnchorDetail,
    booking: () => window.A10Booking,
    status: () => window.A11Status,
    session: () => window.A12Session,
    record: () => window.A13Record,
    tracker: () => window.A14Tracker,
    messages: () => window.A15Messages,
    payments: () => window.A16Payments,
    notifications: () => window.A17Notifications,
    mypage: () => window.A18MyPage,
    'profile-edit': () => window.A19ProfileEdit,
    'email-edit': () => window.A20EmailEdit,
    'password-edit': () => window.A21PasswordEdit,
    'password-reset': () => window.A21PasswordReset,
    'terms-of-service': () => window.A22TermsOfService,
    'privacy-policy': () => window.A23PrivacyPolicy,
    help: () => window.A24Help,
    contact: () => window.A25Contact,
  };
  return map[id]?.();
}

// ── The interactive prototype shell — renders the current screen ──
function PrototypeShell() {
  const nav = useNav();
  const Comp = getScreen(nav.current);

  // hold both for transition
  const t = nav.transition;
  const FromComp = t ? getScreen(t.from) : null;
  const ToComp = t ? getScreen(t.to) : null;

  return (
    <div style={{ width: '100%', height: '100%', position: 'relative', overflow: 'hidden' }}>
      {!t && Comp && <Comp />}
      {t && (
        <>
          <div
            key={`from-${t.from}`}
            style={{
              position: 'absolute',
              inset: 0,
              animation: `ac-${t.dir}-out 240ms ease both`,
            }}>
            {FromComp && <FromComp />}
          </div>
          <div
            key={`to-${t.to}`}
            style={{
              position: 'absolute',
              inset: 0,
              animation: `ac-${t.dir}-in 240ms ease both`,
            }}>
            {ToComp && <ToComp />}
          </div>
        </>
      )}
    </div>
  );
}

// ── Slide transitions ──
if (typeof document !== 'undefined' && !document.getElementById('ac-nav-anim')) {
  const s = document.createElement('style');
  s.id = 'ac-nav-anim';
  s.textContent = `
    @keyframes ac-forward-in { from { transform: translateX(20%); opacity: 0.4 } to { transform: translateX(0); opacity: 1 } }
    @keyframes ac-forward-out { from { transform: translateX(0); opacity: 1 } to { transform: translateX(-8%); opacity: 0.4 } }
    @keyframes ac-back-in { from { transform: translateX(-8%); opacity: 0.4 } to { transform: translateX(0); opacity: 1 } }
    @keyframes ac-back-out { from { transform: translateX(0); opacity: 1 } to { transform: translateX(20%); opacity: 0.4 } }
    @keyframes ac-fade-in { from { opacity: 0 } to { opacity: 1 } }
    @keyframes ac-fade-out { from { opacity: 1 } to { opacity: 0 } }
  `;
  document.head.appendChild(s);
}

// Toast that appears for various notifications
function Toast() {
  const { state, patch } = useAppState();
  const [exiting, setExiting] = React.useState(false);
  
  React.useEffect(() => {
    if (!state.showAddedToast && !state.toastMessage) {
      setExiting(false);
      return;
    }
    
    // Start exit animation after 2 seconds
    const showTimer = setTimeout(() => {
      setExiting(true);
    }, 2000);
    
    // Remove toast after exit animation completes
    const hideTimer = setTimeout(() => {
      patch({ showAddedToast: false, toastMessage: null });
      setExiting(false);
    }, 2400);
    
    return () => {
      clearTimeout(showTimer);
      clearTimeout(hideTimer);
    };
  }, [state.showAddedToast, state.toastMessage, patch]);
  
  const message = state.toastMessage || (state.showAddedToast ? '✓ トラッカーに追加しました' : null);
  if (!message) return null;
  
  return (
    <div
      style={{
        position: 'absolute',
        bottom: 110,
        left: '50%',
        transform: 'translateX(-50%)',
        background: A.ink900,
        color: A.white,
        padding: '10px 16px',
        borderRadius: 100,
        fontSize: 13,
        fontWeight: 500,
        boxShadow: '0 8px 24px rgba(0,0,0,0.2)',
        zIndex: 100,
        animation: exiting ? 'ac-toast-out 400ms ease both' : 'ac-toast-in 240ms ease both',
        whiteSpace: 'nowrap',
      }}>
      {message}
    </div>
  );
}
if (typeof document !== 'undefined' && !document.getElementById('ac-toast-anim')) {
  const s = document.createElement('style');
  s.id = 'ac-toast-anim';
  s.textContent = `
    @keyframes ac-toast-in { from { opacity: 0; transform: translate(-50%, 8px) } to { opacity: 1; transform: translate(-50%, 0) } }
    @keyframes ac-toast-out { from { opacity: 1; transform: translate(-50%, 0) } to { opacity: 0; transform: translate(-50%, 8px) } }
  `;
  document.head.appendChild(s);
}

Object.assign(window, { NavContext, StateContext, NavProvider, useNav, useAppState, PrototypeShell, Toast, TAB_SCREENS, getScreen });
