import React from 'react';
import rehypeReact from 'rehype-react';
import {graphql} from 'gatsby';

import "katex/dist/katex.min.css"

// note - these typographic elements are taken directly from baseui.
// we can consider customizing them by first importing in styled/index, then
// giving them special parameters

import {
  A,
  CodeBlock,
  H1,
  H2,
  H3,
  H4,
  H5,
  H6,
  InlineCode,
  P,
  List,
  ListItem,
  Pre,
  BlockQuote,
  Table,
  TableHeaderCell,
  TableBodyCell,
  MarkdownBody
} from 'gatsby-theme-ocular/components';

const CustomLinkWrapper = relativeLinks => {
  const CustomLink = ({href, ...props}) => {
    if (href.startsWith('http') || href.startsWith('#')) {
      // TODO - we could style them differently though
      return <A href={href} {...props} />;
    }
    const hrefWithoutLeadingSlash = href.startsWith('/') ? href.slice(1) : href;
    return <A {...props} href={relativeLinks[hrefWithoutLeadingSlash]} />;
  };
  return CustomLink;
};

const CustomPre = props => {
  // the point of this component is to distinguish styling of inline <code /> elements
  // with code blocks (ie <pre><code>...</code></pre>).

  const {children, ...otherProps} = props;
  return (
    <Pre {...otherProps}>
      {React.Children.map(children, child => {
        // this means a child of this <pre> element is a <code> element, or <code> element styled
        // by Styletron
        if (
          child.type === 'code' ||
          child.type.displayName === 'Styled(code)'
        ) {
          return <CodeBlock {...child.props} />;
        }
        // else we just clone the element as is
        return React.cloneElement(child);
      })}
    </Pre>
  );
};

// Query for the markdown doc by slug
// (Note: We could just search the allMarkdown from WebsiteConfig ourselves)
export const query = graphql`
  query DocBySlug2($slug: String!) {
    docBySlug2: markdownRemark(fields: {slug: {eq: $slug}}) {
      htmlAst
      timeToRead
      excerpt
      frontmatter {
        title
      }
    }
  }
`;

export default class DocTemplate extends React.Component {
  constructor(props) {
    super(props);
    const {relativeLinks} = props.pageContext;
    // note - we can add many other custom components.

    // without rehypeReact, we'd just render the content of the markdown as generated by gatsby.
    // what this does is that instead we work on the Abstract Syntax Tree (htmlAST).
    // this allows us to replace certain elements by custom components. For instance, if we
    // detect an <h1> element, we will replace it with an H1 custom component. In that case
    // H1 is just a styled version of h1. However, with that process we can implement custom
    // logic. For instance we can rewrite the contents of the link on the fly (CustomLinkWrapper).
    // we can style differently code tags which are within or without a <pre> element. And we can
    // add many more such custom components as needed.
    const renderAst = new rehypeReact({
      createElement: React.createElement,
      components: {
        h1: H1,
        h2: H2,
        h3: H3,
        h4: H4,
        h5: H5,
        h6: H6,
        p: P,
        ul: List,
        li: ListItem,
        pre: CustomPre,
        code: InlineCode,
        table: Table,
        th: TableHeaderCell,
        td: TableBodyCell,
        blockquote: BlockQuote,
        a: CustomLinkWrapper(relativeLinks)
      }
    }).Compiler;
    this.state = {renderAst};
  }

  render() {
    const {htmlAst} = this.props.data.docBySlug2;
    const {renderAst} = this.state;
    return (
      <div>
        <MarkdownBody>{renderAst(htmlAst)}</MarkdownBody>
      </div>
    );
  }
}
