import { WidgetCreator, WidgetArgs } from "vickymd/widget";
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import {
  Card,
  Typography,
  IconButton,
  Box,
  TextField,
  Button,
  Dialog,
  DialogContent,
  DialogActions,
} from "@material-ui/core";
import {
  createStyles,
  makeStyles,
  Theme,
  ThemeProvider,
} from "@material-ui/core/styles";
import clsx from "clsx";
import {
  CardPlus,
  Close,
  ContentSave,
  Cancel,
  Plus,
  TrashCan,
  Pencil,
} from "mdi-material-ui";
import { useTranslation } from "react-i18next";

// @ts-ignore
import Board from "@lourenci/react-kanban";
import { Editor as CodeMirrorEditor } from "codemirror";
import { renderPreview } from "vickymd/preview";
import { selectedTheme } from "../../../themes/manager";
import { setTheme } from "vickymd/theme";
import { crossnoteSettings } from "../../../util/util";
const VickyMD = require("vickymd/core");

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    columnHeader: {
      width: "256px",
      maxWidth: "100%",
      display: "flex",
      alignItems: "center",
      justifyContent: "space-between",
      color: "#000", // BUG: TODO: Wait for react-kanban styling support
    },
    kanbanCard: {
      width: "256px",
      maxWidth: "100%",
      position: "relative",
      backgroundColor: theme.palette.background.paper,
      color: theme.palette.text.primary,
      [theme.breakpoints.down("sm")]: {
        marginTop: "4px",
        marginBottom: "4px",
      },
    },
    editorWrapper: {
      // height: "160px",
      // border: "2px solid #96c3e6",
      "& .CodeMirror-gutters": {
        display: "none",
      },
    },
    textarea: {
      width: "100%",
      height: "100%",
    },
    preview: {
      padding: theme.spacing(2),
    },
  })
);

interface KanbanCard {
  id: number;
  title: string;
  description: string;
}

interface kanbanColumn {
  id: number;
  title: string;
  wip: boolean;
  cards: KanbanCard[];
}

interface KanbanBoard {
  columns: kanbanColumn[];
}

interface KanbanColumnHeaderProps {
  column: kanbanColumn;
  board: KanbanBoard;
  refreshBoard: (board: Board) => void;
  isPreview: boolean;
}

function KanbanColumnHeaderDisplay(props: KanbanColumnHeaderProps) {
  const classes = useStyles(props);
  const { t } = useTranslation();
  const column = props.column;
  const board = props.board;
  const isPreview = props.isPreview;
  const refreshBoard = props.refreshBoard;
  const [clickedTitle, setClickedTitle] = useState<boolean>(false);
  const [titleValue, setTitleValue] = useState<string>(column.title);

  useEffect(() => {
    if (!clickedTitle && titleValue !== column.title) {
      column.title = titleValue || t("general/Untitled");
      setTitleValue(column.title);
      refreshBoard(board);
    }
  }, [clickedTitle, board, column.title, titleValue, t, refreshBoard]);

  return (
    <Box className={clsx(classes.columnHeader)}>
      <Box>
        {clickedTitle ? (
          <TextField
            value={titleValue}
            onChange={(event) => {
              setTitleValue(event.target.value);
            }}
            onBlur={() => {
              setClickedTitle(false);
            }}
            onKeyUp={(event) => {
              if (event.which === 13) {
                setClickedTitle(false);
              }
            }}
          ></TextField>
        ) : (
          <Typography
            variant={"body1"}
            style={{ cursor: "text" }}
            onClick={() => {
              if (!isPreview) {
                setClickedTitle(true);
              }
            }}
          >
            {titleValue}
          </Typography>
        )}
      </Box>
      {!isPreview && (
        <Box>
          <IconButton
            onClick={() => {
              const card: KanbanCard = {
                id: Date.now(),
                title: "", //"Card " + column.cards.length,
                description: t("general/empty"),
              };
              if (column) {
                column.cards.push(card);
              }
              props.refreshBoard(board);
            }}
          >
            <CardPlus></CardPlus>
          </IconButton>
          <IconButton
            onClick={() => {
              board.columns = board.columns.filter((l) => column.id !== l.id);
              props.refreshBoard(board);
            }}
          >
            <Close></Close>
          </IconButton>
        </Box>
      )}
    </Box>
  );
}

interface KanbanCardProps {
  card: KanbanCard;
  board: KanbanBoard;
  refreshBoard: (board: Board) => void;
  isPreview: boolean;
}
function KanbanCardDisplay(props: KanbanCardProps) {
  const classes = useStyles(props);
  const board = props.board;
  const card = props.card;
  const isPreview = props.isPreview;
  const [textAreaElement, setTextAreaElement] = useState<HTMLTextAreaElement>(
    null
  );
  const [previewElement, setPreviewElement] = React.useState<HTMLElement>(null);

  const [editor, setEditor] = useState<CodeMirrorEditor>(null);
  const [description, setDescription] = useState<string>(card.description);
  const [editorDialogOpen, setEditDialogOpen] = useState<boolean>(false);
  const { t } = useTranslation();

  useEffect(() => {
    setDescription(card.description);
  }, [card.description]);

  useEffect(() => {
    if (textAreaElement) {
      const editor: CodeMirrorEditor = VickyMD.fromTextArea(textAreaElement, {
        mode: {
          name: "hypermd",
          hashtag: true,
        },
        keyMap: crossnoteSettings.keyMap,
        showCursorWhenSelecting: true,
        inputStyle: "contenteditable",
      });
      editor.setValue(card.description);
      editor.setOption("lineNumbers", false);
      editor.setOption("foldGutter", false);
      editor.setOption("autofocus", false);
      if (isPreview) {
        editor.setOption("readOnly", "nocursor");
      }
      editor.on("changes", () => {
        setDescription(editor.getValue());
      });
      editor.focus();
      /*
      // Cause save not working
      editor.on("blur", () => {
        setClickedPreview(false);
        setEditor(null);
      });
      */
      // editor.display.input.blur();
      setEditor(editor);
    }
  }, [textAreaElement]);

  useEffect(() => {
    if (editor) {
      setTheme({
        editor,
        themeName: selectedTheme.name,
        baseUri: "/styles/",
      });
    }
  }, [editor]);

  useEffect(() => {
    if (previewElement) {
      renderPreview(previewElement, card.description);
    }
  }, [previewElement]);

  return (
    <Card className={clsx(classes.kanbanCard)}>
      <div
        className={clsx("preview", classes.preview)}
        ref={(element: HTMLElement) => {
          setPreviewElement(element);
        }}
      ></div>
      {!isPreview && (
        <Box style={{ position: "absolute", top: "0", right: "0", zIndex: 99 }}>
          <IconButton onClick={() => setEditDialogOpen(true)}>
            <Pencil></Pencil>
          </IconButton>
          <IconButton
            onClick={() => {
              board.columns.forEach((column) => {
                column.cards = column.cards.filter((c) => c.id !== card.id);
              });
              props.refreshBoard(board);
            }}
          >
            <Close></Close>
          </IconButton>
        </Box>
      )}
      <Dialog
        open={editorDialogOpen}
        onClose={() => setEditDialogOpen(false)}
        style={{ zIndex: 3000 }}
      >
        <DialogContent>
          <Box
            className={clsx(classes.editorWrapper)}
            style={{ minWidth: "300px", maxWidth: "100%" }}
          >
            <textarea
              className={classes.textarea}
              ref={(element: HTMLTextAreaElement) => {
                setTextAreaElement(element);
              }}
            ></textarea>
          </Box>
        </DialogContent>
        <DialogActions>
          <IconButton
            onClick={() => {
              card.description = description;
              props.refreshBoard(props.board);
              setEditDialogOpen(false);
            }}
          >
            <ContentSave></ContentSave>
          </IconButton>
          <IconButton
            onClick={() => {
              if (editor) {
                editor.setValue(card.description);
              }
              setDescription(card.description);
              setEditDialogOpen(false);
            }}
          >
            <Cancel></Cancel>
          </IconButton>
        </DialogActions>
      </Dialog>
    </Card>
  );
}

function KanbanWidget(props: WidgetArgs) {
  const classes = useStyles(props);
  const { t } = useTranslation();
  const [board, setBoard] = useState<KanbanBoard>(
    props.attributes["board"] || {
      columns: [],
    }
  );

  if ("lanes" in (board as any)) {
    board.columns = (board as any).lanes;
  }

  const refreshBoard = (board: KanbanBoard) => {
    const newBoard = Object.assign({}, board);
    props.setAttributes({ board: newBoard });
    setBoard(newBoard as KanbanBoard);
  };

  return (
    <div>
      <Board
        renderColumnHeader={(column: kanbanColumn) => (
          <KanbanColumnHeaderDisplay
            column={column}
            board={board}
            refreshBoard={refreshBoard}
            isPreview={props.isPreview}
          ></KanbanColumnHeaderDisplay>
        )}
        renderCard={(card: KanbanCard, { dragging }: { dragging: boolean }) => {
          return (
            <KanbanCardDisplay
              card={card}
              board={board}
              refreshBoard={refreshBoard}
              isPreview={props.isPreview}
            ></KanbanCardDisplay>
          );
        }}
        allowAddColumn={!props.isPreview}
        allowAddCard={!props.isPreview}
        renderColumnAdder={(): any => {
          return (
            <Box style={{ marginLeft: "16px", marginTop: "16px" }}>
              <Button
                color={"primary"}
                variant={"outlined"}
                onClick={() => {
                  board.columns.push({
                    id: Date.now(),
                    title: t("general/untitled"),
                    cards: [],
                    wip: false,
                  });
                  refreshBoard(board);
                }}
              >
                <Plus></Plus>
                {t("widget/crossnote.kanban/add-column")}
              </Button>
              <Button color={"primary"} onClick={() => props.removeSelf()}>
                <TrashCan></TrashCan>
              </Button>
            </Box>
          );
          // return <ColumnAdder addColumn={addColumn} />;
        }}
        onNewColumnConfirm={(newColumn: any) => {
          board.columns.push({ id: Date.now(), ...newColumn });
          refreshBoard(board);
        }}
        disableCardDrag={props.isPreview}
        disableColumnDrag={props.isPreview}
        onCardDragEnd={(
          card: KanbanCard,
          source: { fromPosition: number; fromColumnId: number },
          destination: { toPosition: number; toColumnId: number }
        ) => {
          const { fromPosition, fromColumnId } = source;
          let { toPosition, toColumnId } = destination;
          const fromColumn = board.columns.filter(
            (l) => l.id === fromColumnId
          )[0];
          const toColumn = board.columns.filter((l) => l.id === toColumnId)[0];
          fromColumn.cards.splice(fromPosition, 1);
          toColumn.cards = [
            ...toColumn.cards.slice(0, toPosition),
            card,
            ...toColumn.cards.slice(toPosition, toColumn.cards.length),
          ];

          refreshBoard(board);
        }}
        onColumnDragEnd={(
          b: KanbanBoard,
          source: { fromPosition: number },
          destination: { toPosition: number }
        ) => {
          const fromPosition: number = source.fromPosition;
          const toPosition: number = destination.toPosition;
          const fromColumn = board.columns[fromPosition];
          const toColumn = board.columns[toPosition];
          board.columns[toPosition] = fromColumn;
          board.columns[fromPosition] = toColumn;
          refreshBoard(board);
        }}
      >
        {board}
      </Board>
    </div>
  );
}

export const KanbanWidgetCreator: WidgetCreator = (args) => {
  const el = document.createElement("span");
  ReactDOM.render(
    <ThemeProvider theme={selectedTheme.muiTheme}>
      <KanbanWidget {...args}></KanbanWidget>
    </ThemeProvider>,
    el
  );
  return el;
};