import styled from "@emotion/styled";
import * as _ from "lodash";
import { inject, observer } from "mobx-react";
import React, { useRef } from "react";
import {
  DragDropContext,
  Draggable,
  DraggableProvided,
  DraggableStateSnapshot,
  Droppable,
} from "react-beautiful-dnd";
import ReactDOM from "react-dom";
import { TiDocumentText } from "react-icons/ti";
import { v4 } from "uuid";
import {
  LIGHT_PRIMARY_THREE,
  LIGHT_SECONDARY_FOUR,
  LIGHT_SHADOW,
} from "../../../shared/colors";
import {
  SlideBoard,
  SlideBoardItemStatus,
  SlideIdea,
  SlideObjectType,
} from "../../../shared/types";
import {
  SlideshowStore,
  SocketActions,
  StoreProps,
} from "../../platform/SlideshowStore";
import withPlatform, { PlatformProps } from "../../platform/withPlatform";
import { canvasStyleDictionary } from "./canvasStyle";
import Resizer from "./Resizer";
import {
  currentKeys,
  CurrentScreen,
  getCanvasPosition,
} from "./windowListeners";

/*
 * 7.9k -> 6.6k -> 6.2k -> 7.7k -> 6.7k Tarzaned
 * 1.8k -> 7.8k -> 18.1k -> 25.8k -> 25.8k Tyler1
 */

const portal: HTMLElement = document.createElement("div");
portal.classList.add("my-super-cool-portal");
document.body.appendChild(portal);

const prefilledText = [{ type: "paragraph", children: [{ text: "" }] }];

type Props = {
  slideBoard: SlideBoard;
  boardItems: SlideIdea[];
} & PlatformProps &
  StoreProps;

type PortalAwareDivProps = {
  provided: DraggableProvided;
  snapshot: DraggableStateSnapshot;
  currentSlideId: string;
  children: any;
};

function PortalAwareDiv(props: PortalAwareDivProps) {
  const child = (
    <PortalDiv
      onMouseDown={(e) => {
        if (e.button !== 1 && !(e.button === 0 && currentKeys["Space"])) {
          e.stopPropagation();
        }
      }}
      ref={props.provided.innerRef}
      {...props.provided.draggableProps}
      {...props.provided.dragHandleProps}
      currentSlideId={
        props.snapshot.isDragging ? props.currentSlideId : undefined
      }
      style={getStyle(props.provided.draggableProps.style, props.snapshot)}
    >
      {props.children}
    </PortalDiv>
  );
  if (!props.snapshot.isDragging) {
    return child;
  }
  return ReactDOM.createPortal(child, portal);
}

function getStyle(style: any, snapshot: DraggableStateSnapshot) {
  if (!snapshot.isDropAnimating) {
    return style;
  }
  return {
    ...style,
    transitionDuration: `0.001s`,
  };
}

// Hell of a function to write
function reorderIndices(
  destination: { id: string; index: number } | null,
  draggableId: string,
  slideBoard: SlideBoard,
  boardItems: SlideIdea[],
  store: SlideshowStore
) {
  const movingBoardItem = boardItems.find(
    (slideIdea) => slideIdea.id === draggableId
  )!;

  const previousStatusItems = boardItems
    .filter((slideIdea) => {
      return (
        slideIdea.status === movingBoardItem.status &&
        slideIdea.id !== movingBoardItem.id
      );
    })
    .map((slideIdea) => {
      if (slideIdea.index > movingBoardItem.index) {
        return {
          ...slideIdea,
          index: slideIdea.index - 1,
        };
      }

      return slideIdea;
    });

  const newItemList = destination
    ? movingBoardItem.status === destination.id
      ? previousStatusItems
      : boardItems.filter((slideIdea) => {
          return (
            slideIdea.status === destination.id &&
            slideIdea.id !== movingBoardItem.id
          );
        })
    : [];

  const newStatusItems = destination
    ? newItemList.map((slideIdea) => {
        if (slideIdea.index >= destination.index) {
          return {
            ...slideIdea,
            index: slideIdea.index + 1,
          };
        }

        return slideIdea;
      })
    : [];

  const updatedItems = destination
    ? movingBoardItem.status === destination.id
      ? newStatusItems
      : [...newStatusItems, ...previousStatusItems]
    : previousStatusItems;

  updatedItems.map((updatedItem) => {
    store.emit(SocketActions.UPDATE_SLIDE_OBJECT, {
      id: updatedItem.id,
      slideId: store.currentSlide.get()!,
      data: updatedItem,
    });
  });
  // We're going to batch update the board items here, which is a bad idea.
  // Probably need a batch update layer to make things smoother

  if (destination) {
    store.emit(SocketActions.UPDATE_SLIDE_OBJECT, {
      id: movingBoardItem.id,
      slideId: store.currentSlide.get()!,
      data: {
        ...movingBoardItem,
        status: destination.id,
        index: destination.index,
      },
    });
  } else {
    store.emit(SocketActions.UPDATE_SLIDE_OBJECT, {
      id: movingBoardItem.id,
      slideId: store.currentSlide.get()!,
      data: {
        ...movingBoardItem,
        boardId: null,
        x: CurrentScreen.createBoardItemCanvasX,
        y: CurrentScreen.createBoardItemCanvasY,
        width: 150,
        height: 50,
      },
    });

    store.emit(SocketActions.UPDATE_SLIDE_OBJECT, {
      id: slideBoard.id,
      slideId: store.currentSlide.get()!,
      data: {
        ...slideBoard,
        boardItems: slideBoard.boardItems.filter(
          (boardItemId) => boardItemId !== movingBoardItem.id
        ),
      },
    });
  }
}

function SlideObjectBoard(props: Props) {
  const boardContainerRef = useRef<HTMLDivElement>(null);

  const currentSlideId = props.store.currentSlide.get()!;

  // React DND is fucking broken - it renders the elements in order that
  // they are presented via .map, not the actual index of the elements.
  const notStartedItems = props.boardItems
    .filter((boardItem) => {
      return boardItem.status === SlideBoardItemStatus.NOT_STARTED;
    })
    .sort((a, b) => {
      return a.index - b.index;
    });

  const inProgressItems = props.boardItems
    .filter((boardItem) => {
      return boardItem.status === SlideBoardItemStatus.IN_PROGRESS;
    })
    .sort((a, b) => {
      return a.index - b.index;
    });

  const completedItems = props.boardItems
    .filter((boardItem) => {
      return boardItem.status === SlideBoardItemStatus.COMPLETED;
    })
    .sort((a, b) => {
      return a.index - b.index;
    });

  return (
    <Resizer
      top={props.slideBoard.y}
      left={props.slideBoard.x}
      width={props.slideBoard.width}
      height={props.slideBoard.height}
      visible={props.store.selectedSlideElement.get() === props.slideBoard.id}
      elementId={props.slideBoard.id}
      store={props.store}
    >
      <BoardContainer
        ref={boardContainerRef}
        onClick={(e) => {
          props.store.setSelectedSlideElement(props.slideBoard.id);
          e.stopPropagation();
        }}
        onMouseDown={(e) => {
          console.log("MOUSE DOWN");
          console.log(e);
          if (
            props.store.selectedSlideElement.get() === props.slideBoard.id &&
            e.button !== 1 &&
            !(e.button === 0 && currentKeys["Space"])
          ) {
            const canvasPosition = getCanvasPosition(e, props.store);
            CurrentScreen.canvasX = canvasPosition.x;
            CurrentScreen.canvasY = canvasPosition.y;
            props.store.currentDragElement.set(props.slideBoard.id);
            e.stopPropagation();
          }
        }}
        onMouseMove={(e) => {}}
        onMouseUp={(e) => {}}
      >
        <ContentContainer>
          <HeaderContainer>
            <Header>
              <CreateNewButton
                onClick={(e) => {
                  const newId = v4();
                  const newData = {
                    status: SlideBoardItemStatus.NOT_STARTED,
                    boardId: props.slideBoard.id,
                    title: "",
                    description: prefilledText,
                    index: notStartedItems.length,
                    type: SlideObjectType.IDEA,
                    x: 0,
                    y: 0,
                    width: 50,
                    height: 50,
                  };
                  props.store.emit(SocketActions.CREATE_SLIDE_OBJECT, {
                    id: newId,
                    slideId: props.store.currentSlide.get()!,
                    ...newData,
                  });
                  props.store.emit(SocketActions.UPDATE_SLIDE_OBJECT, {
                    id: props.slideBoard.id,
                    slideId: props.store.currentSlide.get()!,
                    data: {
                      ...props.slideBoard,
                      boardItems: [...props.slideBoard.boardItems, newId],
                    },
                  });
                  e.stopPropagation();
                }}
              >
                New
              </CreateNewButton>
            </Header>
          </HeaderContainer>
          <Board>
            <DragDropContext
              onDragEnd={(result) => {
                const { source, destination, draggableId } = result;
                reorderIndices(
                  destination
                    ? {
                        id: destination.droppableId,
                        index: destination.index,
                      }
                    : null,
                  draggableId,
                  props.slideBoard,
                  props.boardItems,
                  props.store
                );

                console.log(result);
              }}
            >
              <Column>
                <ColumnHeader>
                  <NotStartedTitle>Not started</NotStartedTitle>
                  <Count>{notStartedItems.length}</Count>
                </ColumnHeader>
                <Break />
                <DragDropContainer>
                  <Droppable droppableId={SlideBoardItemStatus.NOT_STARTED}>
                    {(provided, snapshot) => {
                      return (
                        <BoardColumn
                          {...provided.droppableProps}
                          ref={provided.innerRef}
                        >
                          {notStartedItems.map((boardItem) => (
                            <Draggable
                              key={boardItem.id}
                              draggableId={boardItem.id}
                              index={boardItem.index}
                            >
                              {(provided, snapshot) => {
                                return (
                                  <PortalAwareDiv
                                    provided={provided}
                                    snapshot={snapshot}
                                    currentSlideId={currentSlideId}
                                  >
                                    <BoardItem
                                      empty={!boardItem.title}
                                      onClick={() =>
                                        props.store.showBoardModal.set(
                                          boardItem.id
                                        )
                                      }
                                    >
                                      {!!boardItem.description &&
                                        !_.isEqual(
                                          boardItem.description,
                                          prefilledText
                                        ) && (
                                          <TiDocumentText
                                            style={{ marginRight: 8 }}
                                          />
                                        )}
                                      <BoardTitle>
                                        {boardItem.title || "Untitled"}
                                      </BoardTitle>
                                    </BoardItem>
                                  </PortalAwareDiv>
                                );
                              }}
                            </Draggable>
                          ))}
                        </BoardColumn>
                      );
                    }}
                  </Droppable>
                </DragDropContainer>
              </Column>
              <Column>
                <ColumnHeader>
                  <InProgressTitle>In progress</InProgressTitle>
                  <Count>{inProgressItems.length}</Count>
                </ColumnHeader>
                <Break />
                <DragDropContainer>
                  <Droppable droppableId={SlideBoardItemStatus.IN_PROGRESS}>
                    {(provided, snapshot) => {
                      return (
                        <BoardColumn
                          {...provided.droppableProps}
                          ref={provided.innerRef}
                        >
                          {inProgressItems.map((boardItem) => {
                            return (
                              <Draggable
                                key={boardItem.id}
                                draggableId={boardItem.id}
                                index={boardItem.index}
                              >
                                {(provided, snapshot) => {
                                  return (
                                    <PortalAwareDiv
                                      provided={provided}
                                      snapshot={snapshot}
                                      currentSlideId={currentSlideId}
                                    >
                                      <BoardItem
                                        empty={!boardItem.title}
                                        onClick={() =>
                                          props.store.showBoardModal.set(
                                            boardItem.id
                                          )
                                        }
                                      >
                                        {!!boardItem.description &&
                                          !_.isEqual(
                                            boardItem.description,
                                            prefilledText
                                          ) && (
                                            <TiDocumentText
                                              style={{ marginRight: 8 }}
                                            />
                                          )}
                                        <BoardTitle>
                                          {boardItem.title || "Untitled"}
                                        </BoardTitle>
                                      </BoardItem>
                                    </PortalAwareDiv>
                                  );
                                }}
                              </Draggable>
                            );
                          })}
                        </BoardColumn>
                      );
                    }}
                  </Droppable>
                </DragDropContainer>
              </Column>
              <Column>
                <ColumnHeader>
                  <CompletedTitle>Completed</CompletedTitle>
                  <Count>{completedItems.length}</Count>
                </ColumnHeader>
                <Break />
                <DragDropContainer>
                  <Droppable droppableId={SlideBoardItemStatus.COMPLETED}>
                    {(provided, snapshot) => {
                      return (
                        <BoardColumn
                          {...provided.droppableProps}
                          ref={provided.innerRef}
                        >
                          {completedItems.map((boardItem) => (
                            <Draggable
                              key={boardItem.id}
                              draggableId={boardItem.id}
                              index={boardItem.index}
                            >
                              {(provided, snapshot) => {
                                return (
                                  <PortalAwareDiv
                                    provided={provided}
                                    snapshot={snapshot}
                                    currentSlideId={currentSlideId}
                                  >
                                    <BoardItem
                                      empty={!boardItem.title}
                                      onClick={() =>
                                        props.store.showBoardModal.set(
                                          boardItem.id
                                        )
                                      }
                                    >
                                      {!!boardItem.description &&
                                        !_.isEqual(
                                          boardItem.description,
                                          prefilledText
                                        ) && (
                                          <TiDocumentText
                                            style={{ marginRight: 8 }}
                                          />
                                        )}
                                      <BoardTitle>
                                        {boardItem.title || "Untitled"}
                                      </BoardTitle>
                                    </BoardItem>
                                  </PortalAwareDiv>
                                );
                              }}
                            </Draggable>
                          ))}
                        </BoardColumn>
                      );
                    }}
                  </Droppable>
                </DragDropContainer>
              </Column>
            </DragDropContext>
          </Board>
        </ContentContainer>
      </BoardContainer>
    </Resizer>
  );
}

export default withPlatform(inject("store")(observer(SlideObjectBoard)));

const Count = styled.div`
  margin-left: 8px;
  font-size: 14px;
  color: ${LIGHT_SECONDARY_FOUR};
`;

const PortalDiv = styled.div<{ currentSlideId?: string }>`
  ${(props) =>
    props.currentSlideId &&
    `transform: scale(${canvasStyleDictionary[props.currentSlideId]})`}
`;

const CreateNewButton = styled.div`
  user-select: none;
  cursor: pointer;
  margin-left: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  border-radius: 3px;
  height: 24px;
  color: white;
  line-height: 1.2;
  background: rgb(46, 170, 220);
  padding-left: 8px;
  padding-right: 8px;
  font-size: 14px;
  font-weight: 500;
  transition: 0.12s ease-in-out;
  :hover {
    background: rgb(36, 160, 210);
  }
`;

const NotStartedTitle = styled.div`
  display: inline-flex;
  align-items: center;
  flex-shrink: 1;
  min-width: 0px;
  height: 18px;
  border-radius: 3px;
  padding-left: 6px;
  padding-right: 6px;
  font-size: 14px;
  line-height: 120%;
  color: rgb(55, 53, 47);
  background: rgba(255, 0, 26, 0.2);
  margin: 0px;
`;

const InProgressTitle = styled.div`
  display: inline-flex;
  align-items: center;
  flex-shrink: 1;
  min-width: 0px;
  height: 18px;
  border-radius: 3px;
  padding-left: 6px;
  padding-right: 6px;
  font-size: 14px;
  line-height: 120%;
  color: rgb(55, 53, 47);
  background: rgba(233, 168, 0, 0.2);
  rgba(0, 135, 107, 0.2)
  margin: 0px;
`;

const CompletedTitle = styled.div`
  display: inline-flex;
  align-items: center;
  flex-shrink: 1;
  min-width: 0px;
  height: 18px;
  border-radius: 3px;
  padding-left: 6px;
  padding-right: 6px;
  font-size: 14px;
  line-height: 120%;
  color: rgb(55, 53, 47);
  background: rgba(0, 135, 107, 0.2);
  margin: 0px;
`;

const BoardTitle = styled.div`
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  width: 100%;
`;

const BoardItem = styled.div<{ empty: boolean }>`
  background-color: ${LIGHT_PRIMARY_THREE};
  display: flex;
  align-items: center;
  width: 244px;
  height: 40px;
  border-radius: 4px;
  margin-bottom: 8px;
  box-shadow: 0px 0px 0px 1px rgba(15, 15, 15, 0.1),
    0px 2px 4px rgba(15, 15, 15, 0.1);
  padding-left: 8px;
  padding-right: 8px;
  ${(props) => props.empty && `color: ${LIGHT_SECONDARY_FOUR};`}
`;

const BoardColumn = styled.div`
  display: flex;
  flex-direction: column;
  width: 260px;
  height: 100%;
`;

const DragDropContainer = styled.div`
  height: 100%;
  width: 100%;
`;

const Break = styled.div`
  height: 4px;
`;

const Column = styled.div`
  display: flex;
  flex-direction: column;
  margin-right: 8px;
  :last-of-type {
    margin-right: 0px;
  }
`;

const ColumnHeader = styled.div`
  height: 44px;
  display: flex;
  align-items: center;
`;

const Board = styled.div`
  display: flex;
  width: 100%;
  height: 100%;
  border-top: 1px solid rgba(55, 53, 47, 0.16);
`;

const HeaderContainer = styled.div`
  display: flex;
  height: 42px;
  padding-bottom: 2px;
  align-items: center;
`;

const Header = styled.div`
  display: flex;
  width: 100%;
  align-items: center;
`;

const Title = styled.div``;

const BoardContainer = styled.div`
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: default;
  width: 100%;
  height: 100%;
  background-color: ${LIGHT_PRIMARY_THREE};
  border-radius: 8px;
  box-shadow: 0px 1px 5px 0px ${LIGHT_SHADOW};
`;

const ContentContainer = styled.div`
  display: flex;
  flex-direction: column;
  width: calc(100% - 40px);
  height: calc(100% - 40px);
  margin: 20px;
  background-color: ${LIGHT_PRIMARY_THREE};
`;
