import React, { createContext, useContext, useEffect, useMemo, useCallback } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import { useApp } from '@/entrypoints/popup/context/AppContext';
import { useDb } from '@/entrypoints/popup/context/DbContext';
import { AUTH_FLOW_PATHS } from '@/entrypoints/popup/utils/routes';

import { storage } from '#imports';

const LAST_VISITED_PAGE_KEY = 'session:lastVisitedPage';
const LAST_VISITED_TIME_KEY = 'session:lastVisitedTime';
const NAVIGATION_HISTORY_KEY = 'session:navigationHistory';

type NavigationHistoryEntry = {
  pathname: string;
  search: string;
  hash: string;
};

type NavigationContextType = {
  storeCurrentPage: () => Promise<void>;
  isFullyInitialized: boolean;
  requiresAuth: boolean;
};

const NavigationContext = createContext<NavigationContextType | undefined>(undefined);

/**
 * Navigation provider component that handles storing the last visited page.
 */
export const NavigationProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const location = useLocation();
  const navigate = useNavigate();

  // Auth and DB state
  const { isInitialized: authInitialized, isLoggedIn } = useApp();
  const { dbInitialized, dbAvailable } = useDb();

  // Derived state
  const isFullyInitialized = authInitialized && dbInitialized;
  const requiresAuth = isFullyInitialized && (!isLoggedIn || !dbAvailable);

  /**
   * Store the current page path, timestamp, and navigation history in storage.
   */
  const storeCurrentPage = useCallback(async (): Promise<void> => {
    // Pages that are not allowed to be stored as these are auth conditional pages or dedicated popup pages.
    const notAllowedPaths = [
      ...AUTH_FLOW_PATHS,
      '/auth-settings',
      '/upgrade',
      '/passkeys/create',
      '/passkeys/authenticate'
    ];

    // Only store the page if we're fully initialized and don't need auth
    if (isFullyInitialized && !requiresAuth && !notAllowedPaths.includes(location.pathname)) {
      // Split the path into segments and build up the history
      const segments = location.pathname.split('/').filter(Boolean);
      const historyEntries: NavigationHistoryEntry[] = [];

      // Build history entries for each segment
      let currentPath = '';
      for (let i = 0; i < segments.length; i++) {
        currentPath += '/' + segments[i];

        /*
         * For settings subpages, include both /settings and the subpage
         * For email details, include both /emails and the specific email
         */
        historyEntries.push({
          pathname: currentPath,
          search: location.search,
          hash: location.hash,
        });
      }

      await Promise.all([
        storage.setItem(LAST_VISITED_PAGE_KEY, location.pathname),
        storage.setItem(LAST_VISITED_TIME_KEY, Date.now()),
        storage.setItem(NAVIGATION_HISTORY_KEY, historyEntries),
      ]);
    }
  }, [location, isFullyInitialized, requiresAuth]);

  // Store the current page whenever it changes
  useEffect(() => {
    if (isFullyInitialized) {
      storeCurrentPage();
    }
  }, [location.pathname, location.search, location.hash, isFullyInitialized, storeCurrentPage]);

  // Listen on isloggedin state to redirect to login page if not logged in
  useEffect(() => {
    if (isFullyInitialized && !isLoggedIn) {
      navigate('/login', { replace: true });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isFullyInitialized, isLoggedIn]);

  /*
   * Redirect to /unlock when the vault becomes unavailable from another window
   * (e.g. lock triggered in the main popup while the popout is open). Reinitialize
   * handles the initial-load case, so skip the auth-flow paths.
   */
  useEffect(() => {
    if (isFullyInitialized && isLoggedIn && !dbAvailable && !AUTH_FLOW_PATHS.includes(location.pathname)) {
      navigate('/unlock', { replace: true });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isFullyInitialized, isLoggedIn, dbAvailable, location.pathname]);

  /*
   * If another window has logged in or unlocked the vault,
   * reload the page to reinitialize the app.
   */
  useEffect(() => {
    if (isFullyInitialized && isLoggedIn && dbAvailable && (location.pathname === '/login' || location.pathname === '/unlock')) {
      console.info('[NavigationContext] cross-window session active — leaving auth page', { from: location.pathname });
      navigate('/reinitialize', { replace: true });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isFullyInitialized, isLoggedIn, dbAvailable, location.pathname]);

  // Return the context value
  const contextValue = useMemo(() => ({
    storeCurrentPage,
    isFullyInitialized,
    requiresAuth
  }), [storeCurrentPage, isFullyInitialized, requiresAuth]);

  return (
    <NavigationContext.Provider value={contextValue}>
      {children}
    </NavigationContext.Provider>
  );
};

/**
 * Hook to access the navigation context.
 * @returns The navigation context
 */
export const useNavigation = (): NavigationContextType => {
  const context = useContext(NavigationContext);
  if (context === undefined) {
    throw new Error('useNavigation must be used within a NavigationProvider');
  }
  return context;
};
