/** @jsxImportSource @compiled/react */
import {
  RootLayout,
  VerticalStack,
  Heading,
  mdxComponents,
  ToAnchor,
  AnchorProvider,
  colors,
  PageLink,
  Text,
} from '@compiled/website-ui';
import { MDXProvider } from '@mdx-js/react';
import { useLocation } from 'react-router-dom';
import { LinkItem, Section } from './side-nav';
import { ScrollTop } from './scroll-top';
import { PageTitle } from './page-title';
import { titleCase } from '../utils/string';

function requireAllPages() {
  const req = require.context('../pages');
  return req.keys().reduce(
    (acc, filename) =>
      Object.assign(acc, {
        [filename.replace('./', '').replace('.mdx', '')]: req(filename),
      }),
    {}
  );
}

interface Page {
  default: React.ComponentType<{}>;
  data: {
    headings: {
      depth: number;
      text: string;
    }[];
    order?: number;
    name?: string;
    section: string;
  };
}

const getSections = () => {
  const pages: Record<string, Page> = requireAllPages();
  const sections: Record<string, (Page & { name: string })[]> = {};

  Object.entries(pages)
    .sort(
      (page1, page2) =>
        (page1[1].data.order || 100) - (page2[1].data.order || 100)
    )
    .forEach(([pageName, page]) => {
      const section = page.data.section;
      if (!section) {
        throw new Error(`
Put ${pageName}.mdx in a section! E.g:
---
section: My section
---
      `);
      }

      sections[section] = sections[section] || [];
      sections[section].push({
        ...page,
        name: pageName,
      });
    });

  return Object.entries(sections)
    .sort(([a], [b]) => {
      const aOrder = Number(a.match(/^(\d+)-/)[1] || 100);
      const bOrder = Number(b.match(/^(\d+)-/)[1] || 100);
      return aOrder - bOrder;
    })
    .map(([name, pages]) => ({
      name: name,
      pages,
    }));
};

const getEditUrl = () => {
  const name = location.pathname.split('/')[2] || 'installation';
  return `https://github.com/compiled/compiled-website/tree/master/packages/docs/src/pages/${name}.mdx`;
};

const getPage = (slug: string) => {
  const sections = getSections();
  const name = slug === '/' ? sections[0].pages[0].name : slug.slice(1);
  const pages: Record<string, Page> = requireAllPages();

  const page = pages[name];
  if (!page) {
    return null;
  }

  const sectionIndex = sections.findIndex(
    (section) => section.name === page.data.section
  );
  const previousSection = sections[sectionIndex - 1];
  const nextSection = sections[sectionIndex + 1];
  const section = sections[sectionIndex];
  const pageIndex = section.pages.findIndex((page) => page.name === name);
  const nextPage = section.pages[pageIndex + 1];
  const previousPage = section.pages[pageIndex - 1];

  return {
    name,
    Component: page.default,
    data: page.data,
    next: (nextPage || nextSection) && {
      cta: nextPage ? 'Next' : nextSection.name.replace(/^\d+-/, ''),
      name: nextPage ? nextPage.data.name : nextSection.pages[0].data.name,
      slug: nextPage ? nextPage.name : nextSection.pages[0].name,
    },
    previous: (previousPage || previousSection) && {
      cta: previousPage
        ? 'Previous'
        : previousSection.name.replace(/^\d+-/, ''),
      name: previousPage
        ? previousPage.data.name
        : previousSection.pages[previousSection.pages.length - 1].data.name,
      slug: previousPage
        ? previousPage.name
        : previousSection.pages[previousSection.pages.length - 1].name,
    },
  };
};

export const App = () => {
  const location = useLocation();
  const pageSlug = location.pathname;
  const page = getPage(pageSlug);

  return (
    <AnchorProvider>
      <RootLayout
        aside={
          page && (
            <nav aria-label="page">
              <VerticalStack gap={2}>
                <Heading look="h500" as="div">
                  Contents
                </Heading>
                {page.data.headings
                  .filter((heading) => heading.depth < 4)
                  .map((heading, index) => (
                    <ToAnchor
                      depth={heading.depth}
                      key={`${heading.text}-${index}`}>
                      {heading.text}
                    </ToAnchor>
                  ))}
              </VerticalStack>
            </nav>
          )
        }
        sidenav={
          <>
            {getSections().map((section, sectionIndex) => (
              <Section
                key={section.name}
                title={section.name.replace(/^\d+-/, '')}>
                {section.pages.map((page, pageIndex) => (
                  <LinkItem
                    aria-current={
                      location.pathname === `/${page.name}` ||
                      (location.pathname === '/' &&
                        sectionIndex === 0 &&
                        pageIndex === 0)
                        ? 'page'
                        : undefined
                    }
                    href={`/${page.name}`}
                    key={page.name}>
                    {page.data.name || titleCase(page.name)}
                  </LinkItem>
                ))}
              </Section>
            ))}
          </>
        }>
        <MDXProvider components={mdxComponents}>
          <ScrollTop key={pageSlug} />
          <PageTitle
            title={
              (page && page.data.headings[0].text) ||
              (page && titleCase(page.name))
            }
          />

          {page && (
            <>
              <page.Component />

              <p css={{ margin: '8rem 0' }}>
                <a
                  target="_blank"
                  css={{
                    textDecoration: 'none',
                    borderRadius: 3,
                    color: colors.primary,
                    fontSize: 14,
                    opacity: 0.7,
                    fontWeight: 500,
                  }}
                  href={getEditUrl()}>
                  <Text variant="aside" weight="bold">
                    Suggest changes to this page ➚
                  </Text>
                </a>
              </p>

              <div
                css={{
                  margin: '12rem 0 9rem',
                  display: 'flex',
                  '[data-next="true"]': {
                    marginLeft: 'auto',
                  },
                }}>
                {page.previous && (
                  <PageLink
                    direction="previous"
                    section={page.previous.cta}
                    to={`/${page.previous.slug}`}>
                    {page.previous.name || titleCase(page.previous.slug)}
                  </PageLink>
                )}

                {page.next && (
                  <PageLink
                    direction="next"
                    section={page.next.cta}
                    to={`/${page.next.slug}`}>
                    {page.next.name || titleCase(page.next.slug)}
                  </PageLink>
                )}
              </div>
            </>
          )}
        </MDXProvider>
      </RootLayout>
    </AnchorProvider>
  );
};