import { type ReactNode, createContext, useContext } from 'react';

import { useViewportSize } from '@react-aria/utils';

import { breakpoints } from './tokens';

type TResponsiveContext = {
  atLeastMediumWidth: boolean;
  isNarrowWidth: boolean;
  isSmallWidth: boolean;
  isMediumWidth: boolean;
  isWideWidth: boolean;
  height: number;
  width: number;
};

const ResponsiveContext = createContext<TResponsiveContext>(null);

export function ResponsiveProvider(props: { children: ReactNode }) {
  /*
   * Ensure we render on every viewport size change,
   * even though we're interested in document.documentElement.client<Width|Height>
   * clientWidth/Height are the document size, do not change on pinch-zoom,
   * and are what our `min-width` media queries are reading
   * Viewport size changes on pinch-zoom, which may be useful later when dealing with on-screen keyboards
   */
  useViewportSize();

  const height = document.documentElement.clientHeight;
  const width = document.documentElement.clientWidth;

  // Possible view modes: narrow, small, medium, wide
  // To check if we're at least small width, check !isNarrowWidth
  const viewportInfo = {
    // atLeastMediumWidth is provided to avoid checking (isMediumWidth || isWideWidth)
    atLeastMediumWidth: width >= breakpoints.medium,
    isNarrowWidth: width < breakpoints.small,
    isSmallWidth: width >= breakpoints.small && width < breakpoints.medium,
    isMediumWidth: width >= breakpoints.medium && width < breakpoints.wide,
    // No atLeastWideWidth because that's identical to isWideWidth
    isWideWidth: width >= breakpoints.wide,
    height,
    width,
  };

  return (
    <ResponsiveContext.Provider value={viewportInfo}>
      {props.children}
    </ResponsiveContext.Provider>
  );
}

export function useResponsive() {
  return useContext(ResponsiveContext);
}