import { Alert, Box, Button, CircularProgress } from "@mui/material";
import { useEffect, useRef, useState } from "react";

const State = {
  Loading: 0,
  Ready: 1,
  Error: 2,
} as const;

type State = keyof typeof State;

export function AsyncWidget(p: {
  loadKey: any;
  load: () => Promise<void>;
  errMsg: string;
  build: () => React.ReactElement;
  ready?: boolean;
  errAdditionalElement?: () => React.ReactElement;
}): React.ReactElement {
  const [state, setState] = useState<number>(State.Loading);

  const counter = useRef<any>(null);

  const load = async () => {
    try {
      setState(State.Loading);
      await p.load();
      setState(State.Ready);
    } catch (e) {
      console.error(e);
      setState(State.Error);
    }
  };

  useEffect(() => {
    if (counter.current === p.loadKey) return;
    counter.current = p.loadKey;

    load();
  });

  if (state === State.Error)
    return (
      <Box
        component="div"
        sx={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          height: "100%",
          flex: "1",
          flexDirection: "column",
        }}
      >
        <Alert
          variant="outlined"
          severity="error"
          style={{ margin: "0px 15px 15px 15px" }}
        >
          {p.errMsg}
        </Alert>

        <Button onClick={load}>Try again</Button>

        {p.errAdditionalElement?.()}
      </Box>
    );

  if (state === State.Loading || p.ready === false)
    return (
      <Box
        component="div"
        sx={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          height: "100%",
          flex: "1",
        }}
      >
        <CircularProgress />
      </Box>
    );

  return p.build();
}
