export function createFullscreenController({
  documentTarget = document,
  body = documentTarget.body,
  viewport,
  hint,
  button,
  getHelpersEnabled,
  setHelpersVisible,
  resize,
  restoreLayout,
  resumeVideos,
  requestFrame = requestAnimationFrame,
  setTimer = setTimeout,
  clearTimer = clearTimeout,
}) {
  let active = false;
  let hintTimer = null;
  let savedViewportFlex = null;
  let helpersWereEnabled = false;

  function scheduleTransition(includeLayout) {
    requestFrame(() => setTimer(() => {
      resize();
      if (includeLayout) restoreLayout();
      resumeVideos();
    }, 100));
  }

  function showHint() {
    hint.classList.add('show');
    clearTimer(hintTimer);
    hintTimer = setTimer(() => hint.classList.remove('show'), 3000);
  }

  function hideHint() {
    hint.classList.remove('show');
    clearTimer(hintTimer);
  }

  function enter({ requestNative = true } = {}) {
    if (active) return;
    active = true;
    body.classList.add('fullscreen-mode');
    savedViewportFlex = viewport.style.flex;
    viewport.style.flex = '';
    helpersWereEnabled = getHelpersEnabled();
    if (helpersWereEnabled) setHelpersVisible(false);
    showHint();
    if (requestNative) documentTarget.documentElement?.requestFullscreen?.().catch?.(() => {});
    scheduleTransition(false);
  }

  function exit({ requestNative = true } = {}) {
    if (!active) return;
    active = false;
    body.classList.remove('fullscreen-mode');
    if (savedViewportFlex) viewport.style.flex = savedViewportFlex;
    if (helpersWereEnabled && getHelpersEnabled()) setHelpersVisible(true);
    hideHint();
    if (requestNative && documentTarget.fullscreenElement) {
      documentTarget.exitFullscreen?.().catch?.(() => {});
    }
    scheduleTransition(true);
  }

  function toggle() {
    if (active) exit(); else enter();
  }

  function fullscreenChange() {
    if (!documentTarget.fullscreenElement && active) {
      exit({ requestNative: false });
    } else if (documentTarget.fullscreenElement) {
      if (!active) enter({ requestNative: false });
      else scheduleTransition(false);
    }
  }

  button.addEventListener('click', toggle);
  documentTarget.addEventListener('fullscreenchange', fullscreenChange);

  return {
    enter,
    exit,
    toggle,
    isFullscreen: () => active,
    destroy() {
      button.removeEventListener('click', toggle);
      documentTarget.removeEventListener('fullscreenchange', fullscreenChange);
      clearTimer(hintTimer);
    },
  };
}
