// @flow
// The `useBreakPoint` hook returns a string with the browser's current break point
// value ('sm', 'md', 'lg', or 'xl') and triggers a rerender when it changes.
import { useState, useEffect } from 'react';
import {
  bpMedium,
  bpLarge,
  bpXLarge,
  type BreakPoints,
} from '../../breakpoints';

// These are basically javascript versions of css media queries.
// They let us attach listeners to them so we can respond whenever
// one of the queries change (window resizing).
// https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries
const mdQuery = window.matchMedia(`(min-width: ${bpMedium})`);
const lgQuery = window.matchMedia(`(min-width: ${bpLarge})`);
const xlQuery = window.matchMedia(`(min-width: ${bpXLarge})`);

// Store break point value as a global singleton for easy and efficient access.
let breakPoint: BreakPoints = 'sm';

// Function for setting/updating the breakPoint value.
function updateBreakPoint() {
  if (xlQuery.matches) breakPoint = 'xl';
  else if (lgQuery.matches) breakPoint = 'lg';
  else if (mdQuery.matches) breakPoint = 'md';
  else breakPoint = 'sm';
}

// Initialize breakPoint value for the first time.
updateBreakPoint();

// Store all active setStates in a Set so that we can call them when
// breakPoint changes, and efficiently add and remove setters.
const stateSetters = new Set();

// Handler for break point changes on window resizing.
// Updates breakPoint value and calls registered setters with new value.
function queryChangeHandler() {
  updateBreakPoint();
  stateSetters.forEach(setter => setter(breakPoint));
}

// Register handler with all of the media queries.
mdQuery.addListener(queryChangeHandler);
lgQuery.addListener(queryChangeHandler);
xlQuery.addListener(queryChangeHandler);

export function useBreakPoint(): BreakPoints {
  const setBreakPoint = useState(breakPoint)[1];
  useEffect(() => {
    stateSetters.add(setBreakPoint);
    return () => {
      stateSetters.delete(setBreakPoint);
    };
  }, [setBreakPoint]);

  return breakPoint;
}

// For testing
export { mdQuery as _mdQuery, lgQuery as _lgQuery, xlQuery as _xlQuery };
