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

enum State {
  Loading,
  Ready,
  Error,
}

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(State.Loading);

  const counter = useRef<any | null>(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",
          backgroundColor: (theme) =>
            theme.palette.mode === "light"
              ? theme.palette.grey[100]
              : theme.palette.grey[900],
        }}
      >
        <Alert
          variant="outlined"
          severity="error"
          style={{ margin: "0px 15px 15px 15px" }}
        >
          {p.errMsg}
        </Alert>

        <Button onClick={load}>Réessayer</Button>

        {p.errAdditionalElement && 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",
          backgroundColor: (theme) =>
            theme.palette.mode === "light"
              ? theme.palette.grey[100]
              : theme.palette.grey[900],
        }}
      >
        <CircularProgress />
      </Box>
    );

  return p.build();
}
