import { faCheck } from '@fortawesome/pro-solid-svg-icons/faCheck';
import { faCopy } from '@fortawesome/pro-solid-svg-icons/faCopy';
import clsx from 'clsx';
import Highlight from 'prism-react-renderer';
import Prism from 'prism-react-renderer/prism';
import prismTheme from 'prism-react-renderer/themes/nightOwl';
import { Children, useRef, useState } from 'react';

import { FaIcon } from '../elements/icon/fa-icon';
import * as css from './code-figure.module.scss';

const langDict = {
  js: 'JavaScript',
  jsx: 'JSX',
  yml: 'YAML',
  yaml: 'YAML',
  py: 'Python',
  python: 'Python',
  sh: 'Shell',
  bash: 'Shell',
  zsh: 'Shell',
};

export default function Pre({ children, ...preProps }) {
  const { props: codeProps } = Children.only(children);
  return !codeProps.className ? (
    <pre className={clsx(css.htmlPre)} {...{ children, ...preProps }} />
  ) : (
    <CodeFigure {...{ codeProps, preProps }} />
  );
}

function CodeFigure({ preProps, codeProps }) {
  const [showCopied, setShowCopied] = useState(false);
  const copyBtnRef = useRef(null);
  const copyDivRef = useRef(null);
  function copyCode() {
    const code = copyDivRef.current.innerText;
    window.navigator.clipboard.writeText(code);
    setShowCopied(true);
    setTimeout(() => setShowCopied(false), 1500);
  }
  const langMatch = codeProps.className.match(/\s?language-(.+)\s?/);
  const language = (langMatch && langDict[langMatch[1]]) || langMatch[1];
  const { title, alt, caption = alt, lines = '', children, ...restCodeProps } = codeProps;
  return (
    <figure className={clsx(css.codeFigure, 'f-mono')}>
      {language ? (
        <>
          {title && <div className={clsx(css.codeFigureTitle, 'f-mono')}>{title}</div>}
          <div className={clsx(css.codeFigureMeta)}>
            {language && <span className={clsx(css.codeFigureLanguage, 'f-mono')}>{language}</span>}
            <button
              ref={copyBtnRef}
              type="button"
              aria-label="Copy code to clipboard"
              className={css.copyButton}
              onClick={copyCode}
            >
              {showCopied ? (
                <FaIcon className="fa-fw" icon={faCheck} />
              ) : (
                <FaIcon className="fa-fw" icon={faCopy} />
              )}
            </button>
          </div>
          <pre
            {...preProps}
            className={clsx(
              css.codeFigurePre,
              { [css.codePreHasTitle]: !!title },
              preProps.className,
              'code-figure-pre',
            )}
          >
            <Highlight
              {...{
                Prism,
                code: children.trim(),
                language: langMatch && langMatch[1],
                theme: prismTheme,
              }}
            >
              {({ className, style, tokens, getLineProps, getTokenProps }) => (
                <code
                  {...restCodeProps}
                  className={clsx(
                    // css.codeFigureContent,
                    restCodeProps.className,
                    className,
                    'code-figure-code',
                  )}
                  style={style}
                  ref={copyDivRef}
                >
                  {tokens.map((line, i) => {
                    const lineProps = getLineProps({ line, key: i });
                    lineProps.className = clsx('code-figure-line', lineProps.className, {
                      hilite: lines && lines.includes(i + 1),
                    });
                    // if (lines && lines.includes(i + 1)) {
                    //   lineProps.className = `${lineProps.className} hilite`;
                    // }
                    return (
                      <div key={i} {...lineProps}>
                        {line.map((token, key) => (
                          <span key={key} {...getTokenProps({ token, key })} />
                        ))}
                      </div>
                    );
                  })}
                </code>
              )}
            </Highlight>
          </pre>
        </>
      ) : (
        <pre></pre>
      )}
      {caption && <figcaption className="fg-tone-10">{caption}</figcaption>}
    </figure>
  );
}
