import React from "react";
import { Account, AccountApi, AccountsList } from "../api/AccountApi";
import { AsyncWidget } from "../widgets/AsyncWidget";
import { useSnackbar } from "./context_providers/SnackbarProvider";
import { MovementApi } from "../api/MovementsApi";

interface AccountContext {
  list: AccountsList;
  reload: () => Promise<void>;
  reloadBalances: () => Promise<void>;
  get(id: number): Account | null;
}

const AccountContextK = React.createContext<AccountContext | null>(null);

export function AccountsListProvider(
  p: React.PropsWithChildren
): React.ReactElement {
  const snackbar = useSnackbar();

  const [list, setList] = React.useState<AccountsList | null>(null);

  const loadKey = React.useRef(1);

  const loadPromise = React.useRef<(() => void) | null>(null);

  const load = async () => {
    setList(await AccountApi.GetList());
  };

  const onReload = async () => {
    setList(null);

    loadKey.current += 1;

    return new Promise<void>((res) => {
      loadPromise.current = () => {
        res();
      };
    });
  };

  const reloadBalances = async () => {
    try {
      const balances = await MovementApi.GetAllBalances();
      setList(list!.mapBalances(balances));
    } catch (e) {
      console.error("Failed to reload accounts balance!", e);
      snackbar(`Failed to reload accounts balance! ${e}`);
    }
  };

  return (
    <AsyncWidget
      ready={list !== null}
      loadKey={loadKey.current}
      load={load}
      errMsg="Failed to load the list of accounts!"
      build={() => {
        if (loadPromise.current != null) {
          loadPromise.current();
          loadPromise.current = null;
        }

        return (
          <AccountContextK
            value={{
              list: list!,
              get(id) {
                return list!.get(id);
              },
              reload: onReload,
              reloadBalances,
            }}
          >
            {p.children}
          </AccountContextK>
        );
      }}
    />
  );
}

export function useAccounts(): AccountContext {
  return React.use(AccountContextK)!;
}
