// sort-imports-ignore
// need to disable this for now because of the way prettier formats the file and need to call enableStaticRendering before importing other files
import { enableStaticRendering } from 'mobx-react-lite';
// this is necessary to avoid mobx memory leaks when using server side rendering
// https://mobx.js.org/react-integration.html#tips
enableStaticRendering(typeof window === 'undefined');

import { QueryClient } from '@tanstack/react-query';

import { ApiClient } from '@/lib/apiClient';
import { EventLogger, eventLogger } from '@/utils/event-logger';

import { ClipsStore } from './clipStore';
import { ContestStore } from './contestStore';
import { GenerateFormStore } from './createStore';
import { CreateV2Store } from './createV2Store';
import { DiscoverStore } from './discoverStore';
import { EditStore } from './editStore';
import { FeatureSessionStore } from './featureSessionStore';
import { Ga4Store } from './ga4Store';
import { LibraryStore } from './libraryStore';
import { MenusStore } from './menusStore';
import { NotificationsStore } from './notificationsStore';
import { PersonaStore } from './personaStore';
import { PlaybarStore } from './playbarStore';
import { PlaylistStore } from './playlistStore';
import { ProjectStore } from './projectStore';
import { PromoStore } from './promoStore';
import { QueueStore } from './queueStore';
import { SearchStore } from './searchStore';
import { SessionStore } from './sessionStore';
import { SocialStore } from './socialStore';
import { TagStore } from './tagStore';
import { HashtagStore } from './hashtagStore';
import { TrashStore } from './trashStore';
import { BaseRootStore, BaseSubstore } from './utils';
import { NavigationStore } from '@/state/navigationStore';
import storageAvailable from 'storage-available';

export type Substore = BaseSubstore<RootStore>;

export type Substores = {
  clips: ClipsStore;
  contest: ContestStore;
  discover: DiscoverStore;
  edit: EditStore;
  featureSession: FeatureSessionStore;
  genForm: GenerateFormStore;
  hashtag: HashtagStore;
  library: LibraryStore;
  menus: MenusStore;
  notifications: NotificationsStore;
  persona: PersonaStore;
  playbar: PlaybarStore;
  playlist: PlaylistStore;
  project: ProjectStore;
  promo: PromoStore;
  queue: QueueStore;
  search: SearchStore;
  session: SessionStore;
  social: SocialStore;
  tag: TagStore;
  trash: TrashStore;
  ga4: Ga4Store;
  createV2: CreateV2Store;
  navigation: NavigationStore;
};

export type RootStore = BaseRootStore<Substores>;

/**
 * Creates the root state for the app, including all stores
 */
export default function makeRootStore(
  apiClient: ApiClient,
  queryClient: QueryClient,
  logger: EventLogger = eventLogger // @TODO: Eventually we only need `track`
) {
  let stores: Substores | null = null;

  const isLocalStorageAvailable = storageAvailable('localStorage');
  /**
   * Create the root store proxy that can access the substores created below.
   */
  const rootStore = new Proxy(
    { apiClient, queryClient, logger, isLocalStorageAvailable },
    {
      get(target, prop) {
        // `apiClient` and `logger`
        if (prop in target) {
          return target[prop as keyof typeof target];
        }
        // Easy there, pal.
        if (typeof prop === 'string' && !stores) {
          throw new Error(
            `Cannot access '${String(prop)}' during root store initialization`
          );
        }
        // Substores
        if (stores && prop in stores) {
          return stores[prop as keyof typeof stores];
        }
        // Miss
        return undefined;
      },
    }
  ) as BaseRootStore<Substores>;

  /**
   * Create the substores with a reference to the root state, which allows them
   * to access each other via `this.root`.
   *
   * Note that it is NOT SAFE to access other stores in the `constructor`,
   * since `stores` will not have anything in it yet.
   */
  stores = {
    clips: new ClipsStore(rootStore),
    contest: new ContestStore(rootStore),
    createV2: new CreateV2Store(rootStore),
    discover: new DiscoverStore(rootStore),
    edit: new EditStore(rootStore),
    featureSession: new FeatureSessionStore(rootStore),
    genForm: new GenerateFormStore(rootStore),
    library: new LibraryStore(rootStore),
    menus: new MenusStore(rootStore),
    notifications: new NotificationsStore(rootStore),
    persona: new PersonaStore(rootStore),
    playbar: new PlaybarStore(rootStore),
    playlist: new PlaylistStore(rootStore),
    project: new ProjectStore(rootStore),
    promo: new PromoStore(rootStore),
    queue: new QueueStore(rootStore),
    search: new SearchStore(rootStore),
    session: new SessionStore(rootStore),
    social: new SocialStore(rootStore),
    tag: new TagStore(rootStore),
    hashtag: new HashtagStore(rootStore),
    trash: new TrashStore(rootStore),
    ga4: new Ga4Store(rootStore),
    navigation: new NavigationStore(rootStore),
  } satisfies Substores;

  /**
   * Run any initialization behavior that would have previously run in the
   * `constructor` and requires cross-store access.
   *
   * This feels like kind of a liability, so we may want to just get rid of it
   * altogether in favor of some central state initialization function.
   *
   * In the meantime, please try not to introduce any race conditions.
   */
  Object.values(stores).forEach((store) => {
    if (
      // Only initialize on the client
      typeof window !== 'undefined' &&
      'initialize' in store &&
      typeof store.initialize === 'function'
    ) {
      store.initialize();
    }
  });

  /**
   * Now we have a root store with substores that can access each other.
   */
  return rootStore as BaseRootStore<typeof stores>;
}
