import React from "react";

import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Card from "@mui/material/Card";
import CardActions from "@mui/material/CardActions";
import CardContent from "@mui/material/CardContent";
import { useTheme } from "@mui/material/styles";
import Typography from "@mui/material/Typography";

import { ApiLoadFailedError } from "../api";
import { useI18n } from "../contexts/I18nContext";
import { useUser } from "../contexts/UserContext";

import { PageLoadFailedError } from "./PageLoader";

const errorMessages: Record<number, string> = {
  403: "You are authenticated as %(username)s, but are not authorized to access this page. Would you like to login to a different account?",
  404: "We're sorry, but the requested page could not be found.",
};

interface ErrorScreenProps {
  error: PageLoadFailedError | ApiLoadFailedError | Error | string;
}

interface OnlineErrorScreenProps {
  error: PageLoadFailedError | Error;
}

interface GenericErrorScreenProps extends React.PropsWithChildren {
  header: string;
  description?: string;
}

const GenericErrorScreen: React.FC<GenericErrorScreenProps> = ({
  header,
  description,
  children,
}) => {
  const theme = useTheme();

  return (
    <Box
      sx={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        height: "100%",
        padding: 3,
      }}
    >
      <Card
        sx={{
          boxShadow: 0,
          borderRadius: 3,
          borderWidth: "1px",
          borderStyle: "solid",
          borderColor: theme.palette.divider,
          maxWidth: 800,
        }}
      >
        <CardContent sx={{ ":last-child": { padding: 2 } }}>
          <Typography variant="h6">{header}</Typography>
          {description && <Typography>{description}</Typography>}
        </CardContent>
        {children && <CardActions sx={{ px: 2, pb: 2 }}>{children}</CardActions>}
      </Card>
    </Box>
  );
};

const ErrorScreen: React.FC<ErrorScreenProps> = ({ error }) => {
  if (error instanceof ApiLoadFailedError) {
    return (
      <GenericErrorScreen
        description="There was an error loading the API schema. This may mean that the server is down or that your connection is bad. Please try again later and contact support if this problem persists."
        header="Failed to load essential data"
      >
        <Button
          color="secondary"
          sx={{ ml: "auto" }}
          variant="contained"
          onClick={() => location.reload()}
        >
          Reload
        </Button>
      </GenericErrorScreen>
    );
  }

  if (error instanceof Error) {
    return <OnlineErrorScreen error={error} />;
  }

  return <OnlineErrorScreen error={new Error(error)} />;
};

const OnlineErrorScreen: React.FC<OnlineErrorScreenProps> = ({ error }) => {
  const { t } = useI18n();
  const { user, logout } = useUser();

  return (
    <GenericErrorScreen
      description={
        error instanceof PageLoadFailedError
          ? t(
              error.response.status >= 500
                ? "There's been an error. It's been reported to the site administrators via email and should be fixed shortly. Thanks for your patience."
                : errorMessages[error.response.status],
              user as unknown as Record<string, string>,
            )
          : undefined
      }
      header={`${error.name}: ${error.message}`}
    >
      {error instanceof PageLoadFailedError && error.response.status === 403 && (
        <Button color="secondary" sx={{ ml: "auto" }} variant="contained" onClick={() => logout()}>
          {t("Log in again")}
        </Button>
      )}
    </GenericErrorScreen>
  );
};

export default ErrorScreen;
