import React from "react";
import PropTypes from "prop-types";
import uid from "uuid/v4";
import _ from "lodash";
import { faker } from "@faker-js/faker";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import classNames from "classnames";

import {
  Table,
  Badge,
  Avatar,
  AvatarAddOn,
  Progress,
  Card,
  CardHeader,
  CardTitle,
} from "./../../../../components";
import { randomAvatar, randomArray } from "./../../../../utilities";
import { reorder } from "./utilities";
import classes from "./common.scss";

const allSkills = [
  "JavaScript",
  "Photoshop",
  "Management",
  "Bootstrap",
  "PHP",
  "Sketch",
  "MySQL",
  "Mongo",
  "Node.js",
  "TypeScript",
];

const generateUser = () => ({
  id: uid(),
  name: `${faker.person.firstName()} ${faker.person.lastName()}`,
  title: faker.person.jobType(),
  avatarUrl: randomAvatar(),
  status: randomArray(["success", "warning", "danger"]),
  skills: _.uniq(_.times(_.random(2, 5), () => randomArray(allSkills))),
  interviewProgress: _.random(40, 90),
  portfolio: Math.round(Math.random())
    ? {
        url: "http://webkom.co",
        title: "www.webkom.co",
      }
    : null,
});

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

const getRowClass = (isDragging) =>
  classNames(classes["row"], {
    [classes["row--dragging"]]: isDragging,
  });

// Custom Table Cell - keeps cell width when the row
// is detached from the table
// ========================================================
class TableCell extends React.Component {
  static propTypes = {
    children: PropTypes.node,
    isDragOccurring: PropTypes.bool,
  };

  ref = React.createRef();

  getSnapshotBeforeUpdate(prevProps) {
    if (!this.ref) {
      return null;
    }
    const ref = this.ref.current;

    const isDragStarting =
      this.props.isDragOccurring && !prevProps.isDragOccurring;

    if (!isDragStarting) {
      return null;
    }

    const { width, height } = ref.getBoundingClientRect();

    const snapshot = { width, height };

    return snapshot;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (!this.ref) {
      return;
    }
    const ref = this.ref.current;

    if (snapshot) {
      if (ref.style.width === snapshot.width) {
        return;
      }
      ref.style.width = `${snapshot.width}px`;
      ref.style.height = `${snapshot.height}px`;
      return;
    }

    if (this.props.isDragOccurring) {
      return;
    }

    // inline styles not applied
    if (ref.style.width == null) {
      return;
    }

    // no snapshot and drag is finished - clear the inline styles
    ref.style.removeProperty("height");
    ref.style.removeProperty("width");
  }

  render() {
    // eslint-disable-next-line no-unused-vars
    const { children, isDragOccurring, ...otherProps } = this.props;
    return (
      <td ref={this.ref} {...otherProps}>
        {children}
      </td>
    );
  }
}

// Draggable Table Row
// ========================================================
const DraggableRow = (props) => (
  <Draggable draggableId={props.id} index={props.index}>
    {(provided, snapshot) => (
      <tr
        ref={provided.innerRef}
        {...provided.draggableProps}
        className={getRowClass(snapshot.isDragging)}
      >
        <TableCell
          className="align-middle"
          isDragOccurring={snapshot.isDragging}
          {...provided.dragHandleProps}
        >
          <i className="fa fa-fw fa-arrows-v fa-lg d-block mx-auto text-muted" />
        </TableCell>
        <TableCell
          className="align-middle"
          isDragOccurring={snapshot.isDragging}
        >
          <Avatar.Image
            size="md"
            className="d-block"
            src={props.avatarUrl}
            addOns={[
              <AvatarAddOn.Icon
                className="fa fa-circle"
                color="white"
                key="avatar-icon-bg"
              />,
              <AvatarAddOn.Icon
                className="fa fa-circle"
                color={props.status}
                key="avatar-icon-fg"
              />,
            ]}
          />
        </TableCell>
        <TableCell
          className="align-middle"
          isDragOccurring={snapshot.isDragging}
        >
          <span className="mt-0 h6 mb-1">{props.name}</span>
          <p className="mb-0 text-muted text-truncate">{props.title}</p>
        </TableCell>
        <TableCell
          className="align-middle"
          isDragOccurring={snapshot.isDragging}
        >
          {_.map(props.skills, (skill, index) => (
            <Badge key={index} className={`px-2 ${index > 0 && "ml-1"}`}>
              {skill}
            </Badge>
          ))}
        </TableCell>
        <TableCell
          className="align-middle"
          isDragOccurring={snapshot.isDragging}
        >
          <Progress value={props.interviewProgress} slim />
          <span className="fw-500">{props.interviewProgress}%</span>
        </TableCell>
        <TableCell
          className="text-right align-middle"
          isDragOccurring={snapshot.isDragging}
        >
          {!_.isEmpty(props.portfolio) ? (
            <a href={props.portfolio.url}>{props.portfolio.title}</a>
          ) : (
            <span>-</span>
          )}
        </TableCell>
      </tr>
    )}
  </Draggable>
);
DraggableRow.propTypes = {
  avatarUrl: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  status: PropTypes.string.isRequired,
  skills: PropTypes.array.isRequired,
  interviewProgress: PropTypes.number.isRequired,
  portfolio: PropTypes.object,
  index: PropTypes.number.isRequired,
};

// Demo Component
// ========================================================
const initialState = _.times(5, generateUser);

export class DraggableTable extends React.Component {
  static propTypes = {
    className: PropTypes.string,
  };

  state = {
    users: initialState,
  };

  constructor(props) {
    super(props);

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

  onDragEnd({ source, destination }) {
    if (!destination) {
      return;
    }

    const users = reorder(this.state.users, source.index, destination.index);
    this.setState({ users });
  }

  recoverInitialState() {
    this.setState({
      users: initialState,
    });
  }

  render() {
    return (
      <Card className={this.props.className}>
        <CardHeader className="bg-none bb-0">
          <CardTitle className="h6">Queue of Candidates</CardTitle>
        </CardHeader>
        <DragDropContext onDragEnd={this.onDragEnd}>
          <Table className="mb-0">
            <thead>
              <tr>
                <th className="bt-0"></th>
                <th className="bt-0">Photo</th>
                <th className="bt-0">Name</th>
                <th className="bt-0">Skills</th>
                <th className="bt-0">Interview Passed in</th>
                <th className="bt-0 text-right">Portfolio</th>
              </tr>
            </thead>
            <Droppable droppableId="table">
              {(provided, snapshot) => (
                <tbody
                  ref={provided.innerRef}
                  {...provided.droppableProps}
                  className={getTableClass(snapshot.isDraggingOver)}
                >
                  {_.map(this.state.users, (user, index) => (
                    <DraggableRow key={user.id} index={index} {...user} />
                  ))}
                </tbody>
              )}
            </Droppable>
          </Table>
        </DragDropContext>
      </Card>
    );
  }
}
