import { useEffect, useState } from "react";

import { api } from "../api";
import { AUTH_USER_CHANGED_EVENT, getAuthUserKey } from "../auth";
import { Company } from "../types";
import { useViewResource, ViewResourceError } from "./useViewResource";

let cachedCompanies: Company[] | null = null;
let inflight: Promise<Company[]> | null = null;
let cacheOwner = "";

function resetForOwner(owner: string) {
  if (cacheOwner === owner) return;
  cacheOwner = owner;
  cachedCompanies = null;
  inflight = null;
}

function cachedForCurrentOwner() {
  const owner = getAuthUserKey();
  resetForOwner(owner);
  return cachedCompanies;
}

async function fetchCompanies(): Promise<Company[]> {
  const owner = getAuthUserKey();
  resetForOwner(owner);
  if (cachedCompanies) return cachedCompanies;
  if (inflight) return inflight;

  const request = api
    .get<Company[]>('/companies')
    .then((r) => {
      if (cacheOwner === owner && getAuthUserKey() === owner) cachedCompanies = r.data;
      return r.data;
    })
    .finally(() => {
      if (inflight === request) inflight = null;
    });
  inflight = request;

  return inflight;
}

export function invalidateCompaniesCache() {
  cachedCompanies = null;
  inflight = null;
}

export function useCompanies(): {
  companies: Company[];
  loading: boolean;
  refreshing: boolean;
  error: ViewResourceError | null;
  reload: () => Promise<void>;
} {
  const [cacheBust, setCacheBust] = useState(0);
  const resource = useViewResource(fetchCompanies, {
    initialData: cachedForCurrentOwner() ?? [],
    errorMessage: 'Unable to load companies right now.',
    deps: [cacheBust],
  });

  useEffect(() => {
    if (!resource.error) {
      cachedCompanies = resource.data;
    }
  }, [resource.data, resource.error]);

  useEffect(() => {
    const reloadForAccount = () => {
      resetForOwner(getAuthUserKey());
      setCacheBust((value) => value + 1);
    };
    window.addEventListener(AUTH_USER_CHANGED_EVENT, reloadForAccount);
    return () => window.removeEventListener(AUTH_USER_CHANGED_EVENT, reloadForAccount);
  }, []);

  return {
    companies: resource.data,
    loading: resource.loading,
    refreshing: resource.refreshing,
    error: resource.error,
    reload: async () => {
      invalidateCompaniesCache();
      setCacheBust((value) => value + 1);
    },
  };
}
