export interface DashboardRefreshPauseState {
  visibilityState: DocumentVisibilityState;
  online: boolean;
}

export function shouldPauseDashboardRefresh(
  state: DashboardRefreshPauseState,
): boolean {
  return state.visibilityState !== "visible" || !state.online;
}

export function createDashboardRequestAborter() {
  let shellController: AbortController | undefined;
  let tileController: AbortController | undefined;

  function abortController(controller: AbortController | undefined) {
    if (controller && !controller.signal.aborted) {
      controller.abort();
    }
  }

  return {
    beginShellRun(): AbortSignal {
      abortController(shellController);
      abortController(tileController);
      shellController = new AbortController();
      tileController = undefined;
      return shellController.signal;
    },
    beginTileRun(): AbortSignal {
      abortController(tileController);
      tileController = new AbortController();
      return tileController.signal;
    },
    abortActiveRequests(): void {
      abortController(shellController);
      abortController(tileController);
      shellController = undefined;
      tileController = undefined;
    },
  };
}

type DashboardRefreshEventTarget = Pick<
  EventTarget,
  "addEventListener" | "removeEventListener"
>;

export interface DashboardRefreshLifecycleOptions {
  documentTarget: DashboardRefreshEventTarget;
  windowTarget: DashboardRefreshEventTarget;
  loadDashboard: () => void | Promise<void>;
  pauseRefreshes: () => void;
  refreshPaused: () => boolean;
}

export function attachDashboardRefreshLifecycle(
  options: DashboardRefreshLifecycleOptions,
): () => void {
  function handleRefreshLifecycleChange() {
    if (options.refreshPaused()) {
      options.pauseRefreshes();
      return;
    }

    void options.loadDashboard();
  }

  function handlePageHide() {
    options.pauseRefreshes();
  }

  options.documentTarget.addEventListener(
    "visibilitychange",
    handleRefreshLifecycleChange,
  );
  options.windowTarget.addEventListener("online", handleRefreshLifecycleChange);
  options.windowTarget.addEventListener("offline", handleRefreshLifecycleChange);
  options.windowTarget.addEventListener("pagehide", handlePageHide);

  return () => {
    options.documentTarget.removeEventListener(
      "visibilitychange",
      handleRefreshLifecycleChange,
    );
    options.windowTarget.removeEventListener("online", handleRefreshLifecycleChange);
    options.windowTarget.removeEventListener("offline", handleRefreshLifecycleChange);
    options.windowTarget.removeEventListener("pagehide", handlePageHide);
  };
}
