import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
import { createContext, useContextSelector } from 'use-context-selector';
import {
  buildAppHash,
  parseAppRoute,
  RouteState,
  SettingsSection,
} from '../utils/appRoute';

interface AppRouteContextProps {
  route: RouteState;
  setRoute: (nextRoute: RouteState, options?: { replace?: boolean }) => void;
  openConversationRoute: (conversationId: string) => void;
  openHomeRoute: () => void;
  openSettingsRoute: (section?: SettingsSection) => void;
}

const defaultRoute = parseAppRoute(
  typeof window === 'undefined' ? '#/' : window.location.hash,
);

const AppRouteContext = createContext<AppRouteContextProps>({
  route: defaultRoute,
  setRoute: () => {},
  openConversationRoute: () => {},
  openHomeRoute: () => {},
  openSettingsRoute: () => {},
});

export function AppRouteProvider({ children }: { children: ReactNode }) {
  const [route, setRouteState] = useState<RouteState>(defaultRoute);

  useEffect(() => {
    const handleHashChange = () => {
      setRouteState(parseAppRoute(window.location.hash));
    };

    window.addEventListener('hashchange', handleHashChange);
    handleHashChange();
    return () => window.removeEventListener('hashchange', handleHashChange);
  }, []);

  const setRoute = useCallback((nextRoute: RouteState, options?: { replace?: boolean }) => {
    const nextHash = buildAppHash(nextRoute);
    if (window.location.hash === nextHash) {
      setRouteState(nextRoute);
      return;
    }
    if (options?.replace) {
      window.history.replaceState(null, '', nextHash);
      setRouteState(nextRoute);
      return;
    }
    window.location.hash = nextHash;
  }, []);

  const openConversationRoute = useCallback((conversationId: string) => {
    setRoute({ name: 'conversation', conversationId });
  }, [setRoute]);

  const openHomeRoute = useCallback(() => {
    setRoute({ name: 'home' });
  }, [setRoute]);

  const openSettingsRoute = useCallback((section: SettingsSection = 'account') => {
    setRoute({ name: 'settings', section });
  }, [setRoute]);

  const value = useMemo(() => ({
    route,
    setRoute,
    openConversationRoute,
    openHomeRoute,
    openSettingsRoute,
  }), [openConversationRoute, openHomeRoute, openSettingsRoute, route, setRoute]);

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

export const useAppRouteSelector = <T,>(selector: (state: AppRouteContextProps) => T): T => (
  useContextSelector(AppRouteContext, selector)
);
