import React, {
  createContext,
  ReactNode,
  useCallback,
  useMemo,
  useRef,
} from "react";
import {
  useCurrentScreenData,
  useNavigation,
  useRoute,
  isNavBarVisible,
} from "@applicaster/zapp-react-native-utils/reactHooks";
import { useModalNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ModalNavigationContext";
import { useNestedNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NestedNavigationContext";
import { create } from "zustand";
import { subscribeWithSelector } from "zustand/middleware";
import { useShallow } from "zustand/react/shallow";
import { Animated } from "react-native";

interface NavBarStoreState {
  visible: boolean;
  title: string;
  summary: string;
  setVisible: (state: boolean) => void;
  setTitle: (title: string) => void;
  setSummary: (subtitle: string) => void;
  height: number;
  scrollState: number;
  contentPosition: string;
  scrollYAnimated: Animated.Value;
}

interface NavBarState {
  visible: boolean;
  title: string;
  summary: string;
  setVisible: (state: boolean) => void;
  setTitle: (title: string) => void;
  setSummary: (subtitle: string) => void;
}

const createStateStore = () =>
  create(
    subscribeWithSelector<ScreenStateStore>((set) => ({
      data: {},
      setValue: (key, value) =>
        set((state) => ({
          data: {
            ...state.data,
            [key]: value,
          },
        })),
      removeValue: (key) =>
        set((state) => {
          const newData = { ...state.data };
          delete newData[key];

          return { data: newData };
        }),
    }))
  );

const createStore = () =>
  create<NavBarStoreState>((set) => ({
    title: "",
    summary: "",
    visible: true,
    height: 0,
    scrollState: 0,
    contentPosition: "",
    scrollYAnimated: new Animated.Value(0),
    setTitle(title) {
      set({ title });
    },
    setSummary(summary) {
      set({ summary });
    },
    setVisible(visible) {
      set({ visible });
    },
  }));

const createScreenComponentsStore = () =>
  create(subscribeWithSelector<Record<string, unknown>>((_) => ({})));

const createFeedStore = () =>
  create(subscribeWithSelector<Record<string, unknown>>((_) => ({})));

type ScreenContextType = {
  _navBarStore: ReturnType<typeof createStore>;
  _stateStore: ReturnType<typeof createStateStore>;
  _feedStore: ReturnType<typeof createFeedStore>;
  navBar: NavBarState;
  legacyFormatScreenData: LegacyNavigationScreenData | null;
  /**
   * Zustand store for component-level state within a screen.
   *
   * **Purpose:** Persists state across component mount/unmount cycles (e.g., during virtualization)
   * and enables state sharing between components using the same key within the same screen.
   *
   * **Lifecycle:** Tied to the screen/route — recreated on each route change.
   *
   * @example
   * // Used by useComponentScreenState hook:
   * const store = useScreenContextV2()._componentStateStore;
   * store.setState({ 'my-key': value });
   * const value = store.getState()['my-key'];
   */
  _componentStateStore: ReturnType<typeof createScreenComponentsStore>;
};

export const ScreenContext = createContext<ScreenContextType>({
  _stateStore: createStateStore(),
  _navBarStore: createStore(),
  _feedStore: createFeedStore(),
  navBar: {
    visible: true,
    title: "",
    summary: "",
    setVisible: (_state) => void 0,
    setTitle: (_title) => void 0,
    setSummary: (_subtitle) => void 0,
  },
  legacyFormatScreenData: {} as LegacyNavigationScreenData,
  _componentStateStore: createScreenComponentsStore(),
});

export function ScreenContextProvider({
  children,
  pathname,
}: {
  children: ReactNode;
  pathname: string;
}) {
  const { data, modalData, videoModalState, canGoBack } = useNavigation();

  // There are 4 route scenarios
  // For regular screens take date from navigator stack.
  // is path is model grab screenData from modal state
  // if path is video modal grab screenData from video state
  // if path is hook modal grab screenData from hook state

  const { screenData: routeScreenData } = useRoute();

  const isModal = useModalNavigationContext();
  const isNested = useNestedNavigationContext();
  const currentScreenScreenData = useCurrentScreenData();

  const screenNavBarStateRef = useRef<null | ReturnType<typeof createStore>>(
    null
  );

  const screenStateRef = useRef<null | ReturnType<typeof createStateStore>>(
    null
  );

  const screenFeedStoreRef = useRef<null | ReturnType<typeof createFeedStore>>(
    null
  );

  const getScreenState = useCallback(() => {
    if (screenStateRef.current !== null) {
      return screenStateRef.current;
    }

    const stateStore = createStateStore();
    screenStateRef.current = stateStore;

    return stateStore;
  }, []);

  const getScreenNavBarState = useCallback(() => {
    if (screenNavBarStateRef.current !== null) {
      return screenNavBarStateRef.current;
    }

    const navBarState = createStore();
    screenNavBarStateRef.current = navBarState;

    return navBarState;
  }, []);

  // Assign feed store to ref to persist it across re-renders, but recreate on pathname change
  const screenFeedStore = useMemo(() => createFeedStore(), [pathname]);

  if (screenFeedStoreRef.current !== screenFeedStore) {
    screenFeedStoreRef.current = screenFeedStore;
  }

  // Component state store - recreated when pathname changes (route change).
  // Unlike _navBarStore and _stateStore (cached via refs), this store
  // resets only when pathname changes to provide a clean state for the new route.
  const componentStateStore = useMemo(
    () => createScreenComponentsStore(),
    [pathname]
  );

  const screenNavBarState = getScreenNavBarState()(
    useShallow((state) => ({
      visible: state.visible,
      title: state.title,
      summary: state.summary,
      setTitle: state.setTitle,
      setSummary: state.setSummary,
      setVisible: state.setVisible,
    }))
  );

  const isHook = pathname.includes("hook");

  // screenData is replacement of useScreenContext()
  const screenData = useMemo(() => {
    if (isModal && modalData) return modalData ?? ({} as NavigationScreenData);

    if (isNested && data?.nested) {
      return data?.nested ?? ({} as ScreenData);
    }

    return data ?? ({} as ScreenData);
  }, [isModal, isNested, modalData, data]);

  const isVisible = isNavBarVisible(
    pathname,
    currentScreenScreenData, // what fallback should be if currentScreenData is not available?
    screenNavBarState.visible,
    canGoBack(isHook, pathname),
    videoModalState
  );

  const navBarState = useMemo(
    () => ({
      title: screenNavBarState.title,
      summary: screenNavBarState.summary,
      visible: isVisible,
      setTitle: screenNavBarState.setTitle,
      setSummary: screenNavBarState.setSummary,
      setVisible: screenNavBarState.setVisible,
    }),
    [isVisible, screenNavBarState.title, screenNavBarState.summary]
  );

  return (
    <ScreenContext.Provider
      value={useMemo(
        () => ({
          _navBarStore: getScreenNavBarState(),
          _stateStore: getScreenState(),
          _feedStore: screenFeedStoreRef.current,
          navBar: navBarState,
          legacyFormatScreenData: routeScreenData,
          _componentStateStore: componentStateStore,
        }),
        [navBarState, screenData, routeScreenData, componentStateStore]
      )}
    >
      {children}
    </ScreenContext.Provider>
  );
}

export function withScreenContext(Component: React.ComponentType<any>) {
  return function WithScreenContextWrapper(props) {
    const screenContext = React.useContext(ScreenContext);

    return <Component {...props} screenContext={screenContext} />;
  };
}
