import React, {
  createContext,
  useContext,
  useState,
  useEffect,
  useCallback,
} from "react";
import {
  SiteStatusContextProps,
  SiteStatusProviderProps,
} from "@app/models/components";
import { getSiteStatus } from "@app/services/api";

const SiteStatusContext = createContext<SiteStatusContextProps>(
  {} as SiteStatusContextProps
);

type PatchedFetch = typeof fetch & { __sfsyncSiteStatusPatched?: boolean };

/**
 * Patches window.fetch (once per fetch reference) so that any 403 coming
 * back from a plugin REST call - other than /site-status itself, to avoid a
 * refresh loop - triggers an immediate site-status refresh (see WP-4534).
 */
const installSiteStatusInterceptor = (refresh: () => void) => {
  if (typeof window.fetch !== "function") {
    return;
  }

  const currentFetch = window.fetch as PatchedFetch;

  if (currentFetch.__sfsyncSiteStatusPatched) {
    return;
  }

  const originalFetch = currentFetch;

  const patchedFetch: PatchedFetch = async (...args) => {
    const response = await originalFetch(...args);

    const input = args[0];
    const url =
      typeof input === "string"
        ? input
        : input instanceof Request
        ? input.url
        : String(input);

    const isPluginRequest = url.startsWith(sfsyncRestAPI.baseURL);
    const isSiteStatusRequest = url.includes("/sfsync/v1/site-status");

    if (response.status === 403 && isPluginRequest && !isSiteStatusRequest) {
      refresh();
    }

    return response;
  };

  patchedFetch.__sfsyncSiteStatusPatched = true;
  window.fetch = patchedFetch;
};

export const SiteStatusProvider: React.FC<SiteStatusProviderProps> = ({
  children,
}) => {
  const [isDisabled, setIsDisabled] = useState<boolean>(
    sfsyncData.is_disabled ?? false
  );
  const [disabledSince, setDisabledSince] = useState<number | null>(
    sfsyncData.disabled_since ?? null
  );

  const refreshSiteStatus = useCallback(async () => {
    const result = await getSiteStatus();

    if (result?.error) {
      return;
    }

    setIsDisabled(!!result.disabled);
    setDisabledSince(result.since ?? null);
  }, []);

  useEffect(() => {
    installSiteStatusInterceptor(refreshSiteStatus);
  }, [refreshSiteStatus]);

  useEffect(() => {
    refreshSiteStatus();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <SiteStatusContext.Provider
      value={{ isDisabled, disabledSince, refreshSiteStatus }}
    >
      {children}
    </SiteStatusContext.Provider>
  );
};

export const useSiteStatus = () => {
  return useContext(SiteStatusContext);
};
