import * as React from 'react';
import { AppType, MyAppProps } from 'next/app';
import { default as Document, DocumentContext, DocumentProps, Head, Html, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
import InitColorSchemeScript from '@mui/joy/InitColorSchemeScript';

import { Brand } from '~/common/app.config';
import { createEmotionCache } from '~/common/app.theme';


interface MyDocumentProps extends DocumentProps {
  emotionStyleTags: React.JSX.Element[];
}

export default function MyDocument({ emotionStyleTags }: MyDocumentProps) {
  return (
    <Html lang='en'>
      <Head>
        {/* Meta (missing Title, set by the App or Page) */}
        <meta name='description' content={Brand.Meta.Description} />
        <meta name='theme-color' content={Brand.Meta.ThemeColor} />

        {/* Favicons & PWA */}
        <link rel='shortcut icon' href='/favicon.ico' />
        <link rel='icon' type='image/png' sizes='32x32' href='/icons/favicon-32x32.png' />
        <link rel='icon' type='image/png' sizes='16x16' href='/icons/favicon-16x16.png' />
        <link rel='apple-touch-icon' sizes='180x180' href='/apple-touch-icon.png' />
        <link rel='manifest' href='/manifest.json' />
        <meta name='mobile-web-app-capable' content='yes' />
        <meta name='apple-mobile-web-app-status-bar-style' content='black' />

        {/* Opengraph */}
        <meta property='og:title' content={Brand.Title.Common} />
        <meta property='og:description' content={Brand.Meta.Description} />
        {Brand.URIs.CardImage && <meta property='og:image' content={Brand.URIs.CardImage} />}
        <meta property='og:url' content={Brand.URIs.Home} />
        <meta property='og:site_name' content={Brand.Meta.SiteName} />
        <meta property='og:type' content='website' />

        {/* Twitter / X */}
        <meta name='twitter:card' content='summary_large_image' />
        <meta property='twitter:url' content={Brand.URIs.Home} />
        <meta property='twitter:title' content={Brand.Title.Common} />
        <meta property='twitter:description' content={Brand.Meta.Description} />
        {Brand.URIs.CardImage && <meta property='twitter:image' content={Brand.URIs.CardImage} />}
        <meta name='twitter:site' content={Brand.Meta.TwitterSite} />
        <meta name='twitter:creator' content='@enricoros' />

        {/* Author & Structured Data */}
        <meta name='author' content='Enrico Ros' />
        <link rel='author' href='https://www.enricoros.com' />
        <script type='application/ld+json' dangerouslySetInnerHTML={{ __html: JSON.stringify({
          '@context': 'https://schema.org',
          '@type': 'SoftwareApplication',
          'name': 'Big-AGI',
          'url': 'https://big-agi.com',
          'applicationCategory': 'ProductivityApplication',
          'operatingSystem': 'All, Web',
          'description': Brand.Meta.Description,
          'sameAs': ['https://github.com/enricoros/big-agi', 'https://discord.gg/MkH4qj2Jp9',],
          'author': { '@type': 'Person', 'name': 'Enrico Ros', 'url': 'https://www.enricoros.com' },
          'publisher': { '@type': 'Organization', 'name': 'Token Fabrics LLC', 'url': 'https://www.tokenfabrics.com' },
        }) }} />

        {/* Style Sheets (injected and server-side) */}
        <meta name='emotion-insertion-point' content='' />
        {emotionStyleTags}
      </Head>
      <body>
      <InitColorSchemeScript />
      <Main />
      <NextScript />
      </body>
    </Html>
  );
}

// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with static-site generation (SSG).
MyDocument.getInitialProps = async (ctx: DocumentContext) => {
  // Resolution order
  //
  // On the server:
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. document.getInitialProps
  // 4. app.render
  // 5. page.render
  // 6. document.render
  //
  // On the server with error:
  // 1. document.getInitialProps
  // 2. app.render
  // 3. page.render
  // 4. document.render
  //
  // On the client
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. app.render
  // 4. page.render

  const originalRenderPage = ctx.renderPage;

  // You can consider sharing the same Emotion cache between all the SSR requests to speed up performance.
  // However, be aware that it can have global side effects.
  const cache = createEmotionCache();
  const { extractCriticalToChunks } = createEmotionServer(cache);

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App: React.ComponentType<React.ComponentProps<AppType> & MyAppProps>) =>
        function EnhanceApp(props) {
          return <App emotionCache={cache} {...props} />;
        },
    });

  const initialProps = await Document.getInitialProps(ctx);

  // Inject the comment before the HTML tag
  initialProps.html = `<!-- ❤ Built with Big-AGI -->\n${initialProps.html}`;

  // This is important. It prevents Emotion to render invalid HTML.
  // See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153
  const emotionStyles = extractCriticalToChunks(initialProps.html);
  const emotionStyleTags = emotionStyles.styles.map((style) => (
    <style
      data-emotion={`${style.key} ${style.ids.join(' ')}`}
      key={style.key}
      dangerouslySetInnerHTML={{ __html: style.css }}
    />
  ));

  return {
    ...initialProps,
    emotionStyleTags,
  };
};