import { create } from "zustand";

type ShowLoaderFn = (options?: { opaque?: boolean }) => void;

type HideLoaderFn = () => void;

type SetLoadingFn = (loading: boolean, options?: { opaque?: boolean }) => void;

interface UiState {
  loadingCount: number;
  isLoading: boolean;
  isOpaque: boolean;
  showLoader: ShowLoaderFn;
  hideLoader: HideLoaderFn;
  setLoading: SetLoadingFn;
  setOpaque: (opaque: boolean) => void;
  resetLoading: () => void;
}

export const useUiStore = create<UiState>((set) => ({
  loadingCount: 0,
  isLoading: false,
  isOpaque: false,
  showLoader: (options) =>
    set((state) => {
      const nextCount = state.loadingCount + 1;
      return {
        loadingCount: nextCount,
        isLoading: true,
        // Only set opaque if explicitly passed, otherwise keep current state
        isOpaque: options?.opaque ?? state.isOpaque,
      };
    }),
  hideLoader: () =>
    set((state) => {
      const nextCount = Math.max(state.loadingCount - 1, 0);
      return {
        loadingCount: nextCount,
        isLoading: nextCount > 0,
        // Reset opaque when no more loaders
        isOpaque: nextCount > 0 ? state.isOpaque : false,
      };
    }),
  setLoading: (loading: boolean, options) =>
    set(() =>
      loading
        ? {
            loadingCount: 1,
            isLoading: true,
            isOpaque: options?.opaque ?? false,
          }
        : {
            loadingCount: 0,
            isLoading: false,
            isOpaque: false,
          }
    ),
  setOpaque: (opaque: boolean) => set({ isOpaque: opaque }),
  resetLoading: () =>
    set({ loadingCount: 0, isLoading: false, isOpaque: false }),
}));

export const showGlobalLoader: ShowLoaderFn = (options) => {
  useUiStore.getState().showLoader(options);
};

export const hideGlobalLoader: HideLoaderFn = () => {
  useUiStore.getState().hideLoader();
};

export const setGlobalLoading: SetLoadingFn = (loading: boolean, options) => {
  useUiStore.getState().setLoading(loading, options);
};

export const withGlobalLoading = async <T>(
  operation: () => Promise<T> | T
): Promise<T> => {
  showGlobalLoader();
  try {
    const result = operation();
    return await Promise.resolve(result);
  } finally {
    hideGlobalLoader();
  }
};
