/*
  see
    https://react-syntax-highlighter.github.io/react-syntax-highlighter/demo/prism-async-light.html
    https://github.com/rajinwonderland/react-code-blocks
    https://egghead.io/lessons/react-syntax-highlighting-code-blocks-using-components-with-prism-react-renderer-and-gatsby-mdx
    https://prismjs.com/

  features/workflow to consider
    1. whether to process at build or on client?
    2. how to pass layout options, e.g. layout="hero-right"
    3. whether to support line-highlighting
 */
/*
  PROCESSING HERE

  - FormidableLabs/prism-react-renderer: 🖌️ Renders highlighted Prism output to React (+ theming & vendored Prism)
    https://github.com/FormidableLabs/prism-react-renderer

  - Add line highlighting to prism-react-renderer
    https://prince.dev/highlight-with-react

  METASTRING PARSING

  (see peduarte and XDM)

    API of codeblock
    language (must parse from className)
    title
    caption|alt
    lines
    children = code
 */

import { Children, useRef, useState } from 'react';
import Highlight from 'prism-react-renderer';
import Prism from 'prism-react-renderer/prism';
import prismTheme from 'prism-react-renderer/themes/dracula';
import cn from 'clsx';

import { reporter } from '../utils';
import * as css from './code-block.module.scss';

const languageNames = {
  js: 'JavaScript',
  jsx: 'JavaScript',
  javascript: 'JavaScript',
  yml: 'YAML',
  yaml: 'YAML',
  py: 'Python',
  python: 'Python',
};

export default function CodeBlock({ children, ...preProps }) {
  // const { info } = reporter();
  const [showCopied, setShowCopied] = useState(false);
  const copyBtnRef = useRef(null);
  const copyDivRef = useRef(null);
  function copyCode(ref) {
    const code = copyDivRef.current.innerText;
    window.navigator.clipboard.writeText(code);
    setShowCopied(true);
    setTimeout(() => setShowCopied(false), 1500);
  }
  const {
    props: { title, lines: hiliteLines = [], alt, caption = alt, className, children: code, ...codeProps },
  } = Children.only(children);
  const langMatch = className && className.match(/\s?language-(.+)\s?/);
  const langKey = langMatch ? langMatch[1] : '';
  const langName = langMatch ? languageNames[langKey] || langKey : '';

  return (
    <figure className={cn(css.codeBlockFigure, 'f-mono')} style={{ fontSize: 14 }}>
      {langKey ? (
        <div className={cn(css.codeBlock, 'code-block')}>
          <div className={cn(css.codeBlockLang)}>{langName}</div>
          {/* {title && <div className={css.codeBlockTitle}>{title}</div>}
          <button
            ref={copyBtnRef}
            type="button"
            aria-label="Copy code to clipboard"
            className="code-block-copy-btn"
            onClick={copyCode}
          >
            {showCopied ? 'Copied' : 'Copy'}
          </button> */}
          <Highlight
            {...{
              Prism,
              language: langKey,
              theme: prismTheme,
              code: typeof code == 'string' ? code.trim() : code,
            }}
          >
            {({ className, style, tokens, getLineProps, getTokenProps }) => (
              <pre className={cn(className, css.codeBlockPre)} style={style}>
                <div className="code-block-lines" ref={copyDivRef} {...codeProps}>
                  {tokens.map((line, i) => {
                    if (line.length === 1 && line[0].content === '') {
                      line[0].content = '\n'; // eslint-disable-line no-param-reassign
                    }
                    const lineProps = getLineProps({ line, key: i });

                    if (hiliteLines.includes(i + 1)) {
                      lineProps.className = `${lineProps.className} hilite-line`;
                    }
                    return (
                      <div key={i} {...lineProps}>
                        {line.map((token, key) => (
                          <span key={key} {...getTokenProps({ token, key })} />
                        ))}
                      </div>
                    );
                  })}
                </div>
              </pre>
            )}
          </Highlight>
        </div>
      ) : (
        <pre className={css.plainPre} {...preProps}>
          {children}
        </pre>
      )}
      {caption && <figcaption className="frame">{caption}</figcaption>}
    </figure>
  );
}
