import React from "react";
import PropTypes from "prop-types";
import _ from "lodash";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import uid from "uuid/v4";
import { faker } from "@faker-js/faker";
import classNames from "classnames";
import {
  Card,
  CardHeader,
  CardTitle,
  Media,
  Avatar,
  AvatarAddOn,
} from "./../../../../components";
import { randomAvatar, randomArray } from "./../../../../utilities";
import { reorder, move } from "./utilities";
import classes from "./common.scss";

//  Utility Functions
//=========================================================
const generateItem = () => ({
  id: uid(),
  type: "single",
  name: `${faker.person.firstName()} ${faker.person.lastName()}`,
  title: faker.person.jobType(),
  avatarUrl: randomAvatar(),
  status: randomArray(["success", "warning", "danger"]),
});

const getListClass = (isDraggedOver) =>
  classNames(classes["list"], {
    [classes["list--drag-over"]]: isDraggedOver,
  });

const getItemClass = (isDragging) =>
  classNames(classes["list-group-item"], {
    [classes["list-group-item--dragging"]]: isDragging,
  });

//  Draggable List Component
//=========================================================
const VerticalList = React.memo((props) => {
  return (
    <Droppable droppableId={props.listId}>
      {(provided, snapshot) => (
        <div
          ref={provided.innerRef}
          className={`list-group list-group-flush flex-grow-1 ${getListClass(
            snapshot.isDraggingOver
          )}`}
        >
          {props.items.map((item, index) => (
            <Draggable key={item.id} draggableId={item.id} index={index}>
              {(provided, draggableSnapshot) => (
                <div
                  ref={provided.innerRef}
                  {...provided.draggableProps}
                  {...provided.dragHandleProps}
                  className={`list-group-item ${getItemClass(
                    draggableSnapshot.isDragging
                  )}`}
                >
                  <Media>
                    <Media left className="align-self-center pr-3">
                      <i className="fa fa-ellipsis-v text-muted" />
                    </Media>
                    <Media left middle className="mr-4 align-self-center">
                      <Avatar.Image
                        size="md"
                        className="d-block"
                        src={item.avatarUrl}
                        addOns={[
                          <AvatarAddOn.Icon
                            className="fa fa-circle"
                            color="white"
                            key="avatar-icon-bg"
                          />,
                          <AvatarAddOn.Icon
                            className="fa fa-circle"
                            color={item.status}
                            key="avatar-icon-fg"
                          />,
                        ]}
                      />
                    </Media>
                    <Media body>
                      <span className="mt-0 h6 mb-1">{item.name}</span>
                      <p className="mb-0 text-muted text-truncate">
                        {item.title}
                      </p>
                    </Media>
                  </Media>
                </div>
              )}
            </Draggable>
          ))}
        </div>
      )}
    </Droppable>
  );
});
VerticalList.propTypes = {
  items: PropTypes.array,
  listId: PropTypes.string,
  title: PropTypes.string,
};

//  Draggable Column Component
//=========================================================
class Column extends React.Component {
  static propTypes = {
    children: PropTypes.node,
    id: PropTypes.string,
    index: PropTypes.number,
    title: PropTypes.string,
  };

  render() {
    const { children, id, index, title } = this.props;

    return (
      <Draggable draggableId={id} index={index}>
        {(provided) => (
          <div
            className="col-md-4"
            ref={provided.innerRef}
            {...provided.draggableProps}
          >
            <Card className="h-100">
              <CardHeader {...provided.dragHandleProps} className="b-0 bg-none">
                <CardTitle className="h6 mb-0">
                  <i className="fa fa-ellipsis-v mr-3 text-muted" />
                  {title}
                </CardTitle>
              </CardHeader>
              {children}
            </Card>
          </div>
        )}
      </Draggable>
    );
  }
}

//  Demo Component
//=========================================================
const initialState = {
  listAItems: _.times(_.random(2, 4), generateItem),
  listBItems: _.times(_.random(3, 8), generateItem),
  listCItems: _.times(_.random(3, 8), generateItem),
  lists: [
    { id: "listA", title: "All Candidates" },
    { id: "listB", title: "Candidates Interview" },
    { id: "listC", title: "Candidates Testing" },
  ],
};
export class MultipleVerticalLists extends React.Component {
  static propTypes = {
    className: PropTypes.string,
  };

  state = _.clone(initialState);

  constructor(props) {
    super(props);

    this.onDragEnd = this.onDragEnd.bind(this);
  }

  onDragEnd(result) {
    const { source, destination } = result;

    // Swap column positions
    if (source.droppableId === "board") {
      if (destination.droppableId !== "board") {
        return;
      }
      const lists = reorder(this.state.lists, source.index, destination.index);

      this.setState({ lists });
      return;
    }

    // dropped outside the list
    if (!destination) {
      return;
    }

    // Handle List Items
    if (source.droppableId === destination.droppableId) {
      const items = reorder(
        this.state[`${source.droppableId}Items`],
        source.index,
        destination.index
      );

      this.setState({
        [`${source.droppableId}Items`]: items,
      });
    } else {
      const result = move(
        this.state[`${source.droppableId}Items`],
        this.state[`${destination.droppableId}Items`],
        source,
        destination
      );

      this.setState(_.mapKeys(result, (val, key) => `${key}Items`));
    }
  }

  recoverInitialState() {
    this.setState(initialState);
  }

  render() {
    const { className } = this.props;
    const { lists } = this.state;

    return (
      <div className={className}>
        <DragDropContext onDragEnd={this.onDragEnd}>
          <Droppable droppableId="board" type="COLUMN" direction="horizontal">
            {(provided) => (
              <div
                className="row"
                ref={provided.innerRef}
                {...provided.droppableProps}
              >
                {_.map(lists, (list, index) => (
                  <Column
                    id={list.id}
                    index={index}
                    title={list.title}
                    key={list.id}
                  >
                    <VerticalList
                      listId={list.id}
                      items={this.state[`${list.id}Items`]}
                    />
                  </Column>
                ))}
              </div>
            )}
          </Droppable>
        </DragDropContext>
      </div>
    );
  }
}
