import React, { useMemo } from "react";

import CssBaseline from "@mui/material/CssBaseline";
import { styled, ThemeProvider } from "@mui/material/styles";
import useMediaQuery from "@mui/material/useMediaQuery";

import { MaterialDesignContent, SnackbarProvider } from "notistack";

import { ApiContextProvider } from "./contexts/ApiContext";
import { I18nContextProvider } from "./contexts/I18nContext";
import { UserContextProvider } from "./contexts/UserContext";
import { parentPath } from "./router/routes";
import Admin, { AdminProps } from "./Admin";
import { ApiClient } from "./api";
import { createMainTheme, ThemeTypes } from "./themes";
import { ContribComponentList, ContribComponentMap } from "./types";

export interface AppProps extends AdminProps {
  api:
    | ApiClient
    | string
    | URL
    | {
        schema: string | URL;
        server?: string | URL;
      };
  theme?: ThemeTypes;
  contrib?: ContribComponentMap | ContribComponentList;
}

const StyledSnackbarContent = styled(MaterialDesignContent)(({ theme }) =>
  theme.unstable_sx({
    "&.notistack-MuiContent-default": {
      bgcolor: "primary.main",
    },
    "&.notistack-MuiContent-error": {
      bgcolor: "error.main",
    },
    "&.notistack-MuiContent-warning": {
      bgcolor: "warning.main",
    },
    "&.notistack-MuiContent-info": {
      bgcolor: "info.main",
    },
    "&.notistack-MuiContent-success": {
      bgcolor: "success.main",
    },
  }),
);

export const App: React.FC<AppProps> = ({ theme: userTheme, api, contrib, ...rest }) => {
  const potentialSchema = typeof api === "object" && "schema" in api ? api.schema : api;
  let schemaPath: string | undefined;

  if (typeof potentialSchema === "string" || potentialSchema instanceof URL) {
    try {
      schemaPath = new URL(potentialSchema).pathname;
    } catch {
      // NOTE: This should always be true, but what do I know?
      if (typeof potentialSchema === "string") {
        schemaPath = potentialSchema;
      }
    }
  }

  if (schemaPath != null) {
    rest.basepath ??= parentPath(schemaPath);
  }

  const themeMode = useMediaQuery("(prefers-color-scheme: dark)") ? "dark" : "light";

  const theme = useMemo(() => {
    return createMainTheme(themeMode, userTheme);
  }, [themeMode]);

  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <SnackbarProvider
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "right",
        }}
        Components={{
          default: StyledSnackbarContent,
          error: StyledSnackbarContent,
          warning: StyledSnackbarContent,
          info: StyledSnackbarContent,
          success: StyledSnackbarContent,
        }}
        maxSnack={4}
      >
        <ApiContextProvider api={api} contrib={contrib}>
          <I18nContextProvider>
            <UserContextProvider>
              <Admin {...rest} />
            </UserContextProvider>
          </I18nContextProvider>
        </ApiContextProvider>
      </SnackbarProvider>
    </ThemeProvider>
  );
};

export default App;
