// StaticColorPicker,
import React, { CSSProperties, useEffect, useState } from 'react';
import classNames from 'clsx';
import { createSvgIcon } from '@mui/material';
import { type Editor, useEditorState } from '@tiptap/react';
import {
  ColorLensOutlined,
  DoNotDisturbAltRounded,
  FormatBoldRounded,
  FormatItalicRounded,
  FormatListBulletedRounded,
  FormatListNumberedRounded,
  FormatUnderlinedRounded,
  InsertLinkRounded,
  SquareRounded,
} from '@mui/icons-material';

import {
  Button,
  ClickAwayListener,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  IconButton,
  MenuItem,
  Paper,
  Popper,
  Select,
  Stack,
  StaticColorPicker,
  TextField,
} from '@/mui/components';

import styles from './MenuBar.module.scss';

type Props = {
  editor: Editor;
  disabled?: boolean;
  type: 'title' | 'description';
};

const fontFamilies = [
  {
    label: 'Arial',
    value: 'arial,helvetica,sans-serif',
  },
  {
    label: 'Helvetica',
    value: 'helvetica',
  },
  {
    label: 'Times New Roman',
    value: 'times new roman,times',
  },
  {
    label: 'Times Courier New',
    value: 'courier new,courier',
  },
  {
    label: 'Courier',
    value: 'courier',
  },
];

const fontSizes = Array.from({ length: 15 }, (_, i) => 10 + i);

const colors = [
  '#000000',
  '#6255BA',
  '#52B5D5',
  '#5DB182',
  '#EC6240',
  '#808080',
  '#FF0000',
  '#FFFF00',
  '#008000',
  '#0000FF',
];

const EMPTY_FONT_SIZE = -1;

const TextColorEditorIcon = createSvgIcon(
  <>
    <path fill="var(--internal-color)" d="M20 20H4c-1.1 0-2 .9-2 2s.9 2 2 2h16c1.1 0 2-.9 2-2s-.9-2-2-2" />
    <path d="M7.11 17c.48 0 .91-.3 1.06-.75l1.01-2.83h5.65l.99 2.82c.16.46.59.76 1.07.76.79 0 1.33-.79 1.05-1.52L13.69 4.17C13.43 3.47 12.75 3 12 3s-1.43.47-1.69 1.17L6.06 15.48c-.28.73.27 1.52 1.05 1.52m4.83-11.4h.12l2.03 5.79H9.91z" />
  </>,
  'TextColorEditorIcon',
);

function MenuBar({ editor, disabled, type }: Props) {
  const [colorPickerOpen, setColorPickerOpen] = useState(false);
  const [colorPickerColor, setColorPickerColor] = useState('#000000');

  const [linkOpen, setLinkOpen] = useState(false);
  const [linkUrl, setLinkUrl] = useState('');

  const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

  // Read the current editor's state, and re-render the component when it changes
  const editorState = useEditorState({
    editor,
    selector: (ctx) => ({
      fontSize: parseInt(ctx.editor.getAttributes('textStyle')?.fontSize, 10) || EMPTY_FONT_SIZE,
      fontFamily: ctx.editor.getAttributes('textStyle')?.fontFamily || '',
      color: ctx.editor.getAttributes('textStyle')?.color || '',
      isBold: ctx.editor.isActive('bold') ?? false,
      canBold: ctx.editor.can().chain().toggleBold().run() ?? false,

      isUnderline: ctx.editor.isActive('underline') ?? false,
      canUnderline: ctx.editor.can().chain().toggleUnderline().run() ?? false,

      isItalic: ctx.editor.isActive('italic') ?? false,
      canItalic: ctx.editor.can().chain().toggleItalic().run() ?? false,

      isBulletList: ctx.editor.isActive('bulletList') ?? false,
      isOrderedList: ctx.editor.isActive('orderedList') ?? false,

      isLink: ctx.editor.isActive('link') ?? false,
    }),
  });

  const applyTextStyle = (propertyName: string, value$: string) => {
    const addChain = editor
      .chain()
      .focus()
      .setMark('textStyle', { [propertyName]: value$ });

    if (value$) {
      addChain.run();
    } else {
      addChain.removeEmptyTextStyle().run();
    }
  };

  const applyLink = () => {
    let href = linkUrl.trim();

    if (href && !/^(https?:\/\/|mailto:|tel:)/i.test(href)) {
      href = `https://${href}`;
    }

    if (!href) {
      editor.chain().focus().extendMarkRange('link').unsetLink().run();
    } else {
      editor.chain().focus().extendMarkRange('link').setLink({ href }).run();
    }

    setLinkUrl('');
    setLinkOpen(false);
  };

  useEffect(() => {
    const { dom } = editor.view;

    const handler = (event: KeyboardEvent) => {
      const isK = event.key.toLowerCase() === 'k';

      if ((event.metaKey || event.ctrlKey) && isK) {
        event.preventDefault();

        const current = (editor.getAttributes('link').href as string | undefined) ?? '';
        setLinkUrl(current || '');
        setLinkOpen(true);
      }
    };

    if (type !== 'title' && !disabled) {
      dom.addEventListener('keydown', handler);
    }

    return () => {
      if (dom && handler) {
        dom.removeEventListener('keydown', handler);
      }
    };
  }, [editor, type, disabled]);

  const size = 'medium';

  return (
    <>
      <Stack direction="row" spacing={0} fullWidth alignItems="center" className={styles.Header}>
        <Select
          size={size}
          shape="square"
          value={editorState.fontFamily}
          className={classNames(styles.Select, styles.Select___family)}
          displayEmpty
          onChange={({ target }) => {
            const value = target.value as string;

            applyTextStyle('fontFamily', value || '');
          }}
          disabled={disabled}
        >
          <MenuItem value="">Inherited font</MenuItem>
          {fontFamilies.map(({ label, value }) => (
            <MenuItem key={value} value={value} style={{ fontFamily: value }}>
              {label}
            </MenuItem>
          ))}
        </Select>
        <Divider orientation="vertical" flexItem />
        <Select
          size={size}
          shape="square"
          value={editorState.fontSize}
          displayEmpty
          className={classNames(styles.Select, styles.Select___size)}
          onChange={(e) => {
            const size$ = e.target.value as number;

            applyTextStyle('fontSize', size$ === EMPTY_FONT_SIZE ? '' : `${size$}px`);
          }}
          disabled={disabled}
        >
          <MenuItem value={EMPTY_FONT_SIZE}>Inherited size</MenuItem>
          {fontSizes.map((s) => (
            <MenuItem key={s} value={s}>
              {s}px
            </MenuItem>
          ))}
        </Select>
        <Divider orientation="vertical" flexItem />
        <Button
          size={size}
          color="neutral"
          variant={editorState.isBold ? 'contained' : 'text'}
          shape="square"
          square
          disabled={disabled || !editorState.canBold}
          disableElevation
          startIcon={<FormatBoldRounded />}
          onClick={() => editor.chain().focus().toggleBold().run()}
        />
        <Button
          size={size}
          color="neutral"
          variant={editorState.isItalic ? 'contained' : 'text'}
          shape="square"
          square
          disabled={disabled || !editorState.canItalic}
          disableElevation
          startIcon={<FormatItalicRounded />}
          onClick={() => editor.chain().focus().toggleItalic().run()}
        />
        <Button
          size={size}
          color="neutral"
          variant={editorState.isUnderline ? 'contained' : 'text'}
          shape="square"
          square
          disabled={disabled || !editorState.canUnderline}
          disableElevation
          startIcon={<FormatUnderlinedRounded />}
          onClick={() => editor.chain().focus().toggleUnderline().run()}
        />
        <Button
          size={size}
          square
          shape="square"
          color="neutral"
          variant="text"
          disabled={disabled}
          onClick={(event) => {
            setAnchorEl((p) => (p ? null : (event.target as HTMLElement)));
          }}
          startIcon={
            <TextColorEditorIcon
              style={
                {
                  '--internal-color': editorState.color || '#000000',
                } as CSSProperties
              }
            />
          }
        />
        {anchorEl && (
          <ClickAwayListener onClickAway={() => setAnchorEl(null)}>
            <Popper open={!!anchorEl} anchorEl={anchorEl} placement="bottom-start">
              <Paper elevation={2}>
                <Stack fullWidth spacing={2} className={styles.ColorWrapper}>
                  <Stack direction="row" spacing={0} alignItems="center" justifyContent="center" flexWrap="wrap">
                    {colors.map((htmlColor) => (
                      <IconButton
                        key={htmlColor}
                        size="small"
                        onClick={() => {
                          applyTextStyle('color', htmlColor || '');
                          setAnchorEl(null);
                        }}
                      >
                        <SquareRounded fontSize="x2Large" htmlColor={htmlColor} />
                      </IconButton>
                    ))}
                  </Stack>
                  <Stack fullWidth direction="row" spacing={0} alignItems="center" justifyContent="space-between">
                    <IconButton
                      size="xSmall"
                      onClick={() => {
                        applyTextStyle('color', '');
                        setAnchorEl(null);
                      }}
                    >
                      <DoNotDisturbAltRounded fontSize="xLarge" />
                    </IconButton>

                    <IconButton
                      size="xSmall"
                      onClick={() => {
                        setColorPickerColor(editorState.color || '#000000');
                        setColorPickerOpen(true);
                      }}
                    >
                      <ColorLensOutlined fontSize="xLarge" />
                    </IconButton>
                  </Stack>
                </Stack>
              </Paper>
            </Popper>
          </ClickAwayListener>
        )}
        <Divider orientation="vertical" flexItem />
        {type !== 'title' && (
          <>
            <Button
              size={size}
              color="neutral"
              variant={editorState.isBulletList ? 'contained' : 'text'}
              shape="square"
              square
              disabled={disabled}
              disableElevation
              startIcon={<FormatListBulletedRounded />}
              onClick={() => editor.chain().focus().toggleBulletList().run()}
            />
            <Button
              size={size}
              color="neutral"
              variant={editorState.isOrderedList ? 'contained' : 'text'}
              shape="square"
              square
              disabled={disabled}
              disableElevation
              startIcon={<FormatListNumberedRounded />}
              onClick={() => editor.chain().focus().toggleOrderedList().run()}
            />
            <Divider orientation="vertical" flexItem />
            <Button
              size={size}
              color="neutral"
              variant={editorState.isLink ? 'contained' : 'text'}
              shape="square"
              square
              disabled={disabled}
              disableElevation
              startIcon={<InsertLinkRounded />}
              onClick={() => {
                const current = (editor.getAttributes('link').href as string | undefined) ?? '';
                setLinkUrl(current || '');

                setLinkOpen(true);
              }}
            />
          </>
        )}
      </Stack>
      {colorPickerOpen && (
        <Dialog
          open={colorPickerOpen}
          onClose={() => {
            setColorPickerOpen(false);
            setColorPickerColor('#000000');
          }}
          fullWidth
          maxWidth="sm"
        >
          <DialogTitle
            onClose={() => {
              setColorPickerOpen(false);
              setColorPickerColor('#000000');
            }}
          >
            Select color
          </DialogTitle>
          <DialogContent margin="none">
            <Stack fullWidth justifyContent="center" alignItems="center">
              <StaticColorPicker
                color={colorPickerColor}
                disableAlpha
                onChange={({ hex }) => {
                  setColorPickerColor(hex);
                }}
              />
            </Stack>
          </DialogContent>
          <DialogActions>
            <Button
              variant="outlined"
              size="small"
              onClick={() => {
                setColorPickerOpen(false);
                setColorPickerColor('#000000');
              }}
            >
              Cancel
            </Button>
            <Button
              variant="contained"
              size="small"
              onClick={() => {
                applyTextStyle('color', colorPickerColor || '');
                setColorPickerColor('#000000');
                setColorPickerOpen(false);
              }}
            >
              Apply
            </Button>
          </DialogActions>
        </Dialog>
      )}
      {linkOpen && (
        <Dialog open={linkOpen} onClose={() => setLinkOpen(false)} fullWidth maxWidth="sm">
          <DialogTitle onClose={() => setLinkOpen(false)}>
            {editor.isActive('link') ? 'Edit link' : 'Insert link'}
          </DialogTitle>
          <DialogContent>
            <TextField
              size="small"
              autoFocus
              label="URL"
              fullWidth
              value={linkUrl}
              onChange={(e) => setLinkUrl(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === 'Enter') {
                  e.preventDefault();
                  e.stopPropagation();
                  applyLink();
                  setLinkOpen(false);
                }
                if (e.key === 'Escape') {
                  e.preventDefault();
                  e.stopPropagation();
                  setLinkOpen(false);
                }
              }}
              placeholder="https://example.com"
            />
          </DialogContent>
          <DialogActions>
            {editor.isActive('link') && (
              <Button
                color="error"
                size="small"
                onClick={() => {
                  editor.chain().focus().extendMarkRange('link').unsetLink().run();
                  setLinkUrl('');
                  setLinkOpen(false);
                }}
              >
                Remove
              </Button>
            )}
            <Button variant="outlined" size="small" onClick={() => setLinkOpen(false)}>
              Cancel
            </Button>
            <Button variant="contained" size="small" onClick={applyLink}>
              Apply
            </Button>
          </DialogActions>
        </Dialog>
      )}
    </>
  );
}

export default MenuBar;
