import { MDXProvider } from "@mdx-js/react";
import { NextComponentType, NextPageContext } from "next";
import { AppProps as DefaultAppProps } from "next/app";
import React, { ComponentType, ReactNode } from "react";

import { Blockquote } from "@/components/Blockquote";
import { Button } from "@/components/Button";
import { Code } from "@/components/Code";
import { DefaultLayout } from "@/components/DefaultLayout";
import { Footer } from "@/components/Footer";
import { HorizontalLine } from "@/components/HorizontalLine";
import { Image } from "@/components/Image";
import { Link } from "@/components/Link";
import { Navbar } from "@/components/Navbar";
import { Pre } from "@/components/Pre";
import {
  defaultGetShapesConfig,
  GetShapesConfig,
  ShapesBackground,
} from "@/components/ShapesBackground";
import { Table } from "@/components/Table";
import { ThemeProvider } from "@/components/Theme";

import styles from "./_app.module.css";

import "./_app.css";
import "./font.css";

export default function App({ Component, pageProps }: AppProps): JSX.Element {
  const Layout = Component.Layout ?? DefaultLayout;

  return (
    <ThemeProvider>
      <MDXProvider
        components={{
          a: Link,
          hr: HorizontalLine,
          button: Button,
          pre: Pre,
          inlineCode: Code,
          img: Image,
          table: Table,
          blockquote: Blockquote,
        }}
      >
        <div className={styles.appContainer}>
          <Navbar />
          {/* Wrapping content with a div to allow for a display: block parent */}
          <div className={styles.contentContainer}>
            <ShapesBackground
              getConfig={Component.getShapesConfig ?? defaultGetShapesConfig}
            />
            <Layout>
              <Component {...pageProps} />
            </Layout>
          </div>
          <Footer />
        </div>
      </MDXProvider>
    </ThemeProvider>
  );
}

type PageComponent = NextComponentType<
  NextPageContext,
  unknown,
  Record<string, unknown>
> & {
  Layout?: ComponentType<{ children: ReactNode }>;
  getShapesConfig?: GetShapesConfig;
};

type AppProps = DefaultAppProps & {
  Component: PageComponent;
};
