import { Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import styled, { AnyStyledComponent, css } from 'styled-components';
import { WagmiConfig } from 'wagmi';
import { QueryClient, QueryClientProvider } from 'react-query';
import { GrazProvider } from 'graz';

import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';

import {
  useBreakpoints,
  useTokenConfigs,
  useInitializePage,
  useShouldShowFooter,
  useAnalytics,
} from '@/hooks';
import { DydxProvider } from '@/hooks/useDydxClient';
import { AccountsProvider } from '@/hooks/useAccounts';
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
import { LocaleProvider } from '@/hooks/useLocaleSeparators';
import { NotificationsProvider } from '@/hooks/useNotifications';
import { LocalNotificationsProvider } from '@/hooks/useLocalNotifications';
import { RestrictionProvider } from '@/hooks/useRestrictions';
import { SubaccountProvider } from '@/hooks/useSubaccount';
import { SquidProvider } from '@/hooks/useSquid';

import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';

import MarketsPage from '@/pages/markets/Markets';
import PortfolioPage from '@/pages/portfolio/Portfolio';
import { AlertsPage } from '@/pages/AlertsPage';
import ProfilePage from '@/pages/Profile';
import { SettingsPage } from '@/pages/settings/Settings';
import TradePage from '@/pages/trade/Trade';
import { RewardsPage } from '@/pages/rewards/RewardsPage';
import { TermsOfUsePage } from '@/pages/TermsOfUsePage';
import { PrivacyPolicyPage } from '@/pages/PrivacyPolicyPage';

import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
import { FooterMobile } from '@/layout/Footer/FooterMobile';
import { NotificationsToastArea } from '@/layout/NotificationsToastArea';
import { DialogManager } from '@/layout/DialogManager';
import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';

import { config } from '@/lib/wagmi';

import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';

import '@/styles/constants.css';
import '@/styles/fonts.css';
import '@/styles/web3modal.css';

const queryClient = new QueryClient();

const Content = () => {
  const { setDialogArea } = useDialogArea();

  useInitializePage();
  useAnalytics();

  const { isTablet, isNotTablet } = useBreakpoints();
  const isShowingHeader = isNotTablet;
  const isShowingFooter = useShouldShowFooter();
  const { chainTokenLabel } = useTokenConfigs();

  return (
    <Styled.Content isShowingHeader={isShowingHeader} isShowingFooter={isShowingFooter}>
      {isNotTablet && <HeaderDesktop />}

      <Styled.Main>
        <Suspense fallback={null}>
          <Routes>
            <Route path={AppRoute.Trade}>
              <Route path=":market" element={<TradePage />} />
              <Route path={AppRoute.Trade} element={<TradePage />} />
            </Route>

            <Route path={AppRoute.Markets} element={<MarketsPage />} />
            <Route path={`/${chainTokenLabel}`} element={<RewardsPage />} />
            {isTablet && (
              <>
                <Route path={AppRoute.Alerts} element={<AlertsPage />} />
                <Route path={AppRoute.Profile} element={<ProfilePage />} />
                <Route path={`${AppRoute.Settings}/*`} element={<SettingsPage />} />
              </>
            )}

            <Route element={<GuardedMobileRoute />}>
              <Route path={`${AppRoute.Portfolio}/*`} element={<PortfolioPage />} />
            </Route>

            <Route path={AppRoute.Terms} element={<TermsOfUsePage />} />
            <Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} />

            <Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} />
          </Routes>
        </Suspense>
      </Styled.Main>

      {isTablet ? <FooterMobile /> : <FooterDesktop />}

      <Styled.NotificationsToastArea />

      <Styled.DialogArea ref={setDialogArea}>
        <DialogManager />
      </Styled.DialogArea>

      <GlobalCommandDialog />
    </Styled.Content>
  );
};

const wrapProvider = (Component: React.ComponentType<any>, props?: any) => {
  // eslint-disable-next-line react/display-name
  return ({ children }: { children: React.ReactNode }) => (
    <Component {...props}>{children}</Component>
  );
};

const providers = [
  wrapProvider(QueryClientProvider, { client: queryClient }),
  wrapProvider(GrazProvider),
  wrapProvider(WagmiConfig, { config }),
  wrapProvider(LocaleProvider),
  wrapProvider(RestrictionProvider),
  wrapProvider(DydxProvider),
  wrapProvider(AccountsProvider),
  wrapProvider(SubaccountProvider),
  wrapProvider(SquidProvider),
  wrapProvider(LocalNotificationsProvider),
  wrapProvider(NotificationsProvider),
  wrapProvider(DialogAreaProvider),
];

const App = () => {
  return [...providers].reverse().reduce((children, Provider) => {
    return <Provider>{children}</Provider>;
  }, <Content />);
};

const Styled: Record<string, AnyStyledComponent> = {};

Styled.Content = styled.div<{ isShowingHeader: boolean; isShowingFooter: boolean }>`
  /* Computed */
  --page-currentHeaderHeight: 0px;
  --page-currentFooterHeight: 0px;

  ${({ isShowingHeader }) =>
    isShowingHeader &&
    css`
      --page-currentHeaderHeight: var(--page-header-height);

      @media ${breakpoints.tablet} {
        --page-currentHeaderHeight: var(--page-header-height-mobile);
      }
    `}

  ${({ isShowingFooter }) =>
    isShowingFooter &&
    css`
      --page-currentFooterHeight: var(--page-footer-height);

      @media ${breakpoints.tablet} {
        --page-currentFooterHeight: var(--page-footer-height-mobile);
      }
    `}

  /* Rules */
  ${layoutMixins.contentContainer}

  ${layoutMixins.scrollArea}
  --scrollArea-height: 100vh;

  @supports (-webkit-touch-callout: none) {
    height: -webkit-fill-available;
  }

  ${layoutMixins.stickyArea0}
  --stickyArea0-topHeight: var(--page-currentHeaderHeight);
  --stickyArea0-topGap: var(--border-width);
  --stickyArea0-bottomGap: var(--border-width);
  --stickyArea0-bottomHeight: var(--page-currentFooterHeight);

  ${layoutMixins.withOuterAndInnerBorders}
  display: grid;
  grid-template:
    'Header' var(--page-currentHeaderHeight)
    'Main' minmax(min-content, 1fr)
    'Footer' var(--page-currentFooterHeight)
    / 100%;

  transition: 0.3s var(--ease-out-expo);
`;

Styled.Main = styled.main`
  ${layoutMixins.contentSectionAttached}

  grid-area: Main;

  isolation: isolate;

  position: relative;
`;

Styled.NotificationsToastArea = styled(NotificationsToastArea)`
  grid-area: Main;
  z-index: 2;
`;

Styled.DialogArea = styled.aside`
  position: fixed;
  height: 100%;
  z-index: 1;
  inset: 0;
  overflow: clip;
  ${layoutMixins.noPointerEvents}
`;

export default App;
