import { createContext, useContext, useState } from 'react';

type AppState = {
  openDialogs: string[];
  getCurrentDialog: () => string | null;
  openDialog: (id: string, callback: () => void) => void;
  closeDialog: (id: string, callback: () => void) => void;
};

const initialState: AppState = {
  /**
   * This context is necessary to work with react-admin standard forms when executed
   * inside a dialog and deeper in another resource handled inside a primary form.
   *
   * In this case, when using "EditInDialogButton" or "CreateInDialogButton" components,
   * the dialog is opened and the form is rendered inside it. If the form has a subform
   * and needs to know the associated resource.
   */
  openDialogs: [],
  getCurrentDialog: () => null,
  openDialog: (id: string, callback: () => void): void => {
    throw new Error(`openDialog not yet ready for: ${id}, ${callback}`);
  },
  closeDialog: (id: string, callback: () => void): void => {
    throw new Error(`closeDialog not yet ready for: ${id}, ${callback}`);
  }
};

const AppStateContext = createContext<AppState>(initialState);

type AppStateProviderProps = {
  children: React.ReactNode;
};

function AppStateProvider(props: AppStateProviderProps) {
  const [config, setConfig] = useState<AppState>(initialState);
  function openDialog(id: string, callback: () => void) {
    setConfig((config: AppState) => ({ ...config, openDialogs: [...config.openDialogs, id] }));
    if (callback) callback();
  }
  function closeDialog(id: string, callback: () => void) {
    setConfig((config: AppState) => ({
      ...config,
      openDialogs: config.openDialogs.filter((modalId) => modalId !== id)
    }));
    if (callback) callback();
  }

  function getCurrentDialog(): string | null {
    return config.openDialogs.length > 0 ? config.openDialogs[config.openDialogs.length - 1] : null;
  }

  return (
    <AppStateContext.Provider
      value={{
        ...config,
        openDialog,
        closeDialog,
        getCurrentDialog
      }}
    >
      {props.children}
    </AppStateContext.Provider>
  );
}

function useAppState(): AppState {
  const context = useContext(AppStateContext);
  if (context === undefined) {
    throw new Error('useAppState must be used within an AppStateProvider');
  }
  return context;
}
/**
 * Hook to get the current application configuration.
 * This is an alias for useAppState.
 */
function useAppConfig(): AppState {
  const appState = useAppState();
  return appState;
}

export type { AppState };
export { AppStateContext, AppStateProvider, useAppConfig, useAppState };
