import React, { FC, useState, useMemo, ReactDOM } from 'react';
import { EditorState, EditorBlock, Modifier } from 'draft-js';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import { ToastContainer, toast } from 'react-toastify';
import RichIcon from '../RichIcon/RichIcon';
import Styles from './code.module.scss';
import 'react-toastify/dist/ReactToastify.css';

const alias = {
  javascript: 'js',
  jsx: 'js',
};

interface SwitchContainerProps {
  onClickOutside?: () => void;
  onClick?: (event: any) => void;
  children: ReactDOM;
}

const SwitchContainer: FC<SwitchContainerProps> = props => {
  const { onClick, onClickOutside, children } = props;
  const handleClickOutside = () => {
    onClickOutside();
  };
  return (
    <div contentEditable={false} onClick={onClick}>
      {children}
    </div>
  );
};

export interface CodeProps {
  block: { getKey: () => any };
  blockProps: {
    setEditorState: any;
    renderLanguageSelect: any;
    languages: any;
    language: any;
    getEditorState: EditorState;
    readOnly: boolean;
  };
}

const CodeBlock: FC<CodeProps> = props => {
  const [isOpen, setIsOpen] = useState(false);
  const [isCopied, setIsCopied] = useState(false);
  const [isDown, setIsDown] = useState(false);
  const { blockProps, block } = props;
  const {
    getEditorState,
    setEditorState,
    readOnly,
    languages,
    renderLanguageSelect,
  } = blockProps;

  let { language } = blockProps;
  language = alias[language] || language;
  const selectedLabel = languages[language];
  const selectedValue = language;

  const copyValue = useMemo(() => (block as any).getText(), [block]);

  const options = Object.keys(languages).reduce(
    (acc, val) => [
      ...acc,
      {
        label: languages[val],
        value: val,
      },
    ],
    []
  );

  const onChange = (ev): void => {
    ev.preventDefault();
    ev.stopPropagation();
    setIsOpen(false);

    const blockKey = block.getKey();
    const editorState = getEditorState;
    const selection = editorState.getSelection();
    const language = ev.currentTarget.value;
    const blockSelection = selection.merge({
      anchorKey: blockKey,
      focusKey: blockKey,
    });

    let currentContent = editorState.getCurrentContent();
    currentContent = Modifier.mergeBlockData(currentContent, blockSelection, {
      language,
    } as any);

    const newEditorState = EditorState.push(
      editorState,
      currentContent,
      'change-block-data'
    );

    setEditorState(newEditorState);
  };

  const onSelectClick = (ev): void => {
    setIsOpen(true);
    ev.stopPropagation();
  };

  const onClickOutside = (): void => {
    if (isOpen === false) return;
    setIsOpen(false);
    const { getEditorState, setEditorState } = blockProps;

    const editorState = getEditorState;
    const selection = editorState.getSelection();

    setEditorState(EditorState.forceSelection(editorState, selection));
  };

  const handleCopyCode = (e: Event) => {
    e.stopPropagation();
    e.preventDefault();
    const plainText = (block as any).getText();
    const oDiv = document.createElement('div');
    oDiv.innerText = plainText;
    document.body.appendChild(oDiv);
    const range = document.createRange();
    window.getSelection().removeAllRanges();
    range.selectNode(oDiv);
    oDiv.style.position = 'absolute';
    oDiv.style.top = '9999';
    window.getSelection().addRange(range);
    document.execCommand('Copy');
    oDiv.remove();
  };

  const handleMouseDown = (): void => {
    toast('✅复制成功!', {
      position: 'top-center',
      autoClose: 700,
      hideProgressBar: true,
      closeOnClick: true,
      pauseOnHover: true,
      draggable: true,
      progress: undefined,
    });
    setIsDown(true);
  };

  return (
    <pre className="language-xxx">
      <EditorBlock {...props} />

      <CopyToClipboard
        contentEditable={false}
        text={copyValue}
        onCopy={() => setIsCopied(true)}
      >
        <div
          contentEditable={false}
          className={Styles.copy}
          onMouseDown={handleMouseDown}
          onMouseUp={() => {
            setIsDown(false);
          }}
        >
          <RichIcon
            type="icon-fuzhi"
            contentEditable={false}
            className={`${Styles.copyBtn} ${isDown ? Styles.btnDown : ''}`}
          ></RichIcon>
        </div>
      </CopyToClipboard>

      <ToastContainer className={Styles.toast} />

      {!readOnly && (
        <SwitchContainer
          onClickOutside={onClickOutside}
          onClick={onSelectClick}
        >
          {renderLanguageSelect({
            selectedLabel,
            selectedValue,
            onChange,
            options,
          })}
        </SwitchContainer>
      )}
    </pre>
  );
};

export default CodeBlock;