import "@mantine/core/styles.css";
import "@mantine/code-highlight/styles.css";
import "@mantine/notifications/styles.css";
import "@mantine/dates/styles.css";
import classes from "./App.module.css";
import PrometheusLogo from "./images/prometheus-logo.svg";

import {
  AppShell,
  Box,
  Burger,
  Button,
  Group,
  MantineProvider,
  Menu,
  Skeleton,
  Text,
  createTheme,
  rem,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import {
  IconBellFilled,
  IconChevronDown,
  IconChevronRight,
  IconCloudDataConnection,
  IconDatabase,
  IconFlag,
  IconHeartRateMonitor,
  IconInfoCircle,
  IconSearch,
  IconServer,
  IconServerCog,
} from "@tabler/icons-react";
import {
  BrowserRouter,
  Link,
  NavLink,
  Navigate,
  Route,
  Routes,
} from "react-router-dom";
import { IconTable } from "@tabler/icons-react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import QueryPage from "./pages/query/QueryPage";
import AlertsPage from "./pages/AlertsPage";
import RulesPage from "./pages/RulesPage";
import TargetsPage from "./pages/targets/TargetsPage";
import StatusPage from "./pages/StatusPage";
import TSDBStatusPage from "./pages/TSDBStatusPage";
import FlagsPage from "./pages/FlagsPage";
import ConfigPage from "./pages/ConfigPage";
import AgentPage from "./pages/AgentPage";
import { Suspense } from "react";
import ErrorBoundary from "./components/ErrorBoundary";
import { ThemeSelector } from "./components/ThemeSelector";
import { Notifications } from "@mantine/notifications";
import { useAppDispatch } from "./state/hooks";
import { updateSettings, useSettings } from "./state/settingsSlice";
import SettingsMenu from "./components/SettingsMenu";
import ReadinessWrapper from "./components/ReadinessWrapper";
import { QueryParamProvider } from "use-query-params";
import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6";
import ServiceDiscoveryPage from "./pages/service-discovery/ServiceDiscoveryPage";

const queryClient = new QueryClient();

const navIconStyle = { width: rem(16), height: rem(16) };

const mainNavPages = [
  {
    title: "Query",
    path: "/query",
    icon: <IconSearch style={navIconStyle} />,
    element: <QueryPage />,
    inAgentMode: false,
  },
  {
    title: "Alerts",
    path: "/alerts",
    icon: <IconBellFilled style={navIconStyle} />,
    element: <AlertsPage />,
    inAgentMode: false,
  },
];

const monitoringStatusPages = [
  {
    title: "Target health",
    path: "/targets",
    icon: <IconHeartRateMonitor style={navIconStyle} />,
    element: <TargetsPage />,
    inAgentMode: true,
  },
  {
    title: "Rule health",
    path: "/rules",
    icon: <IconTable style={navIconStyle} />,
    element: <RulesPage />,
    inAgentMode: false,
  },
  {
    title: "Service discovery",
    path: "/service-discovery",
    icon: <IconCloudDataConnection style={navIconStyle} />,
    element: <ServiceDiscoveryPage />,
    inAgentMode: true,
  },
];

const serverStatusPages = [
  {
    title: "Runtime & build information",
    path: "/status",
    icon: <IconInfoCircle style={navIconStyle} />,
    element: <StatusPage />,
    inAgentMode: true,
  },
  {
    title: "TSDB status",
    path: "/tsdb-status",
    icon: <IconDatabase style={navIconStyle} />,
    element: <TSDBStatusPage />,
    inAgentMode: false,
  },
  {
    title: "Command-line flags",
    path: "/flags",
    icon: <IconFlag style={navIconStyle} />,
    element: <FlagsPage />,
    inAgentMode: true,
  },
  {
    title: "Configuration",
    path: "/config",
    icon: <IconServerCog style={navIconStyle} />,
    element: <ConfigPage />,
    inAgentMode: true,
  },
];

const allStatusPages = [...monitoringStatusPages, ...serverStatusPages];

const theme = createTheme({
  colors: {
    "codebox-bg": [
      "#f5f5f5",
      "#e7e7e7",
      "#cdcdcd",
      "#b2b2b2",
      "#9a9a9a",
      "#8b8b8b",
      "#848484",
      "#717171",
      "#656565",
      "#575757",
    ],
  },
});

// This dynamically/generically determines the pathPrefix by stripping the first known
// endpoint suffix from the window location path. It works out of the box for both direct
// hosting and reverse proxy deployments with no additional configurations required.
const getPathPrefix = (path: string) => {
  if (path.endsWith("/")) {
    path = path.slice(0, -1);
  }

  const pagePaths = [
    ...mainNavPages,
    ...allStatusPages,
    { path: "/agent" },
  ].map((p) => p.path);

  const pagePath = pagePaths.find((p) => path.endsWith(p));
  return path.slice(0, path.length - (pagePath || "").length);
};

const navLinkXPadding = "md";

function App() {
  const [opened, { toggle }] = useDisclosure();

  const pathPrefix = getPathPrefix(window.location.pathname);
  const dispatch = useAppDispatch();
  dispatch(updateSettings({ pathPrefix }));

  const { agentMode } = useSettings();

  const navLinks = (
    <>
      {mainNavPages
        .filter((p) => !agentMode || p.inAgentMode)
        .map((p) => (
          <Button
            key={p.path}
            component={NavLink}
            to={p.path}
            className={classes.link}
            leftSection={p.icon}
            px={navLinkXPadding}
          >
            {p.title}
          </Button>
        ))}

      <Menu shadow="md" width={240}>
        <Routes>
          {allStatusPages
            .filter((p) => !agentMode || p.inAgentMode)
            .map((p) => (
              <Route
                key={p.path}
                path={p.path}
                element={
                  <Menu.Target>
                    <Button
                      component={NavLink}
                      to={p.path}
                      className={classes.link}
                      leftSection={p.icon}
                      rightSection={<IconChevronDown style={navIconStyle} />}
                      px={navLinkXPadding}
                    >
                      Status <IconChevronRight style={navIconStyle} /> {p.title}
                    </Button>
                  </Menu.Target>
                }
              />
            ))}
          <Route
            path="*"
            element={
              <Menu.Target>
                <Button
                  component={NavLink}
                  to="/"
                  className={classes.link}
                  leftSection={<IconServer style={navIconStyle} />}
                  rightSection={<IconChevronDown style={navIconStyle} />}
                  onClick={(e) => {
                    e.preventDefault();
                  }}
                  px={navLinkXPadding}
                >
                  Status
                </Button>
              </Menu.Target>
            }
          />
        </Routes>

        <Menu.Dropdown>
          <Menu.Label>Monitoring status</Menu.Label>
          {monitoringStatusPages
            .filter((p) => !agentMode || p.inAgentMode)
            .map((p) => (
              <Menu.Item
                key={p.path}
                component={NavLink}
                to={p.path}
                leftSection={p.icon}
              >
                {p.title}
              </Menu.Item>
            ))}

          <Menu.Divider />
          <Menu.Label>Server status</Menu.Label>
          {serverStatusPages
            .filter((p) => !agentMode || p.inAgentMode)
            .map((p) => (
              <Menu.Item
                key={p.path}
                component={NavLink}
                to={p.path}
                leftSection={p.icon}
              >
                {p.title}
              </Menu.Item>
            ))}
        </Menu.Dropdown>
      </Menu>

      {/* <Button
        component="a"
        href="https://prometheus.io/docs/prometheus/latest/getting_started/"
        className={classes.link}
        leftSection={<IconHelp style={navIconStyle} />}
        target="_blank"
        px={navLinkXPadding}
      >
        Help
      </Button> */}
    </>
  );

  return (
    <BrowserRouter basename={pathPrefix}>
      <QueryParamProvider adapter={ReactRouter6Adapter}>
        <MantineProvider defaultColorScheme="auto" theme={theme}>
          <Notifications position="top-right" />

          <QueryClientProvider client={queryClient}>
            <AppShell
              header={{ height: 56 }}
              navbar={{
                width: 300,
                // TODO: On pages with a long title like "/status", the navbar
                // breaks in an ugly way for narrow windows. Fix this.
                breakpoint: "sm",
                collapsed: { desktop: true, mobile: !opened },
              }}
              padding="md"
            >
              <AppShell.Header bg="rgb(65, 73, 81)" c="#fff">
                <Group h="100%" px="md">
                  <Group style={{ flex: 1 }} justify="space-between">
                    <Group gap={65}>
                      <Link
                        to="/"
                        style={{ textDecoration: "none", color: "white" }}
                      >
                        <Group gap={10} wrap="nowrap">
                          <img src={PrometheusLogo} height={30} />
                          <Text fz={20}>Prometheus{agentMode && " Agent"}</Text>
                        </Group>
                      </Link>
                      <Group gap={12} visibleFrom="sm">
                        {navLinks}
                      </Group>
                    </Group>
                    <Group visibleFrom="xs">
                      <ThemeSelector />
                      <SettingsMenu />
                    </Group>
                  </Group>
                  <Burger
                    opened={opened}
                    onClick={toggle}
                    hiddenFrom="sm"
                    size="sm"
                    color="gray.2"
                  />
                </Group>
              </AppShell.Header>

              <AppShell.Navbar py="md" px={4} bg="rgb(65, 73, 81)" c="#fff">
                {navLinks}
                <Group mt="md" hiddenFrom="xs" justify="center">
                  <ThemeSelector />
                  <SettingsMenu />
                </Group>
              </AppShell.Navbar>

              <AppShell.Main>
                <ErrorBoundary key={location.pathname}>
                  <Suspense
                    fallback={
                      <Box mt="lg">
                        {Array.from(Array(10), (_, i) => (
                          <Skeleton
                            key={i}
                            height={40}
                            mb={15}
                            width={1000}
                            mx="auto"
                          />
                        ))}
                      </Box>
                    }
                  >
                    <Routes>
                      <Route
                        path="/"
                        element={
                          <Navigate
                            to={agentMode ? "/agent" : "/query"}
                            replace
                          />
                        }
                      />
                      {agentMode ? (
                        <Route
                          path="/agent"
                          element={
                            <ReadinessWrapper>
                              <AgentPage />
                            </ReadinessWrapper>
                          }
                        />
                      ) : (
                        <>
                          <Route
                            path="/query"
                            element={
                              <ReadinessWrapper>
                                <QueryPage />
                              </ReadinessWrapper>
                            }
                          />
                          <Route
                            path="/alerts"
                            element={
                              <ReadinessWrapper>
                                <AlertsPage />
                              </ReadinessWrapper>
                            }
                          />
                        </>
                      )}
                      {allStatusPages.map((p) => (
                        <Route
                          key={p.path}
                          path={p.path}
                          element={
                            <ReadinessWrapper>{p.element}</ReadinessWrapper>
                          }
                        />
                      ))}
                    </Routes>
                  </Suspense>
                </ErrorBoundary>
              </AppShell.Main>
            </AppShell>
            {/* <ReactQueryDevtools initialIsOpen={false} /> */}
          </QueryClientProvider>
        </MantineProvider>
      </QueryParamProvider>
    </BrowserRouter>
  );
}

export default App;
