import { useRef, useState } from "react";
import PropTypes from "prop-types";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import * as actions from "../../../../redux/trello/trello.actions.js";
import { Draggable, Droppable } from "../dnd/lib";
import { Virtuoso, VirtuosoGrid } from "react-virtuoso";
import HeightPreservingItem from "../components/HeightPreservingItem.jsx";
import { Section } from "../styles/Base.js";
import LaneFooter from "../components/LaneFooter.jsx";
import { EyeInvisibleOutlined, EyeOutlined } from "@ant-design/icons";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../../../redux/user/user.selectors.js";
import { selectTechnician } from "../../../../redux/tech/tech.selectors.js";
import ProductionBoardCard from "../../production-board-kanban-card.component.jsx";
import HeightMemoryWrapper from "../components/HeightMemoryWrapper.jsx";
import SizeMemoryWrapper from "../components/SizeMemoryWrapper.jsx";
import ListComponent from "../components/ListComponent.jsx";
import ItemComponent from "../components/ItemComponent.jsx";
import ItemWrapper from "../components/ItemWrapper.jsx";
import objectHash from "object-hash";

/**
 * Lane is a React component that represents a lane in a Trello-like board.
 * @param id
 * @param title
 * @param index
 * @param isProcessing
 * @param laneSortFunction
 * @param cards
 * @param cardSettings
 * @param orientation
 * @param maxLaneHeight
 * @param setMaxLaneHeight
 * @param maxCardHeight
 * @param setMaxCardHeight
 * @param maxCardWidth
 * @param setMaxCardWidth
 * @param lastDrag
 * @param technician -- connected to redux
 * @param bodyshop -- connected to redux
 * @returns {Element}
 * @constructor
 */
const Lane = ({
  id,
  title,
  index,
  isProcessing,
  laneSortFunction,
  cards,
  cardSettings = {},
  orientation = "vertical",
  maxLaneHeight,
  setMaxLaneHeight,
  maxCardHeight,
  setMaxCardHeight,
  maxCardWidth,
  setMaxCardWidth,
  lastDrag,
  technician,
  bodyshop
}) => {
  const [collapsed, setCollapsed] = useState(false);
  const laneRef = useRef(null);

  let sortedCards = cards || [];
  if (laneSortFunction && cards) {
    sortedCards = [...cards].sort(laneSortFunction);
  }

  const toggleLaneCollapsed = () => {
    setCollapsed((prevCollapsed) => !prevCollapsed);
  };

  const renderDraggable = (index, card) => {
    if (!card) {
      console.log("null card");
      return null;
    }
    return (
      <Draggable draggableId={card.id} index={index} key={card.id} isDragDisabled={isProcessing}>
        {(provided, snapshot) => (
          <div
            {...provided.draggableProps}
            {...provided.dragHandleProps}
            ref={provided.innerRef}
            style={provided.draggableProps.style}
            className={`item ${snapshot.isDragging ? "is-dragging" : ""}`}
            key={card.id}
          >
            <SizeMemoryWrapper
              maxHeight={maxCardHeight}
              setMaxHeight={setMaxCardHeight}
              maxWidth={maxCardWidth}
              setMaxWidth={setMaxCardWidth}
            >
              <ProductionBoardCard
                technician={technician}
                bodyshop={bodyshop}
                cardSettings={cardSettings}
                key={card.id}
                card={card}
                style={{ minHeight: maxCardHeight, minWidth: maxCardWidth }}
                className="react-trello-card"
              />
            </SizeMemoryWrapper>
          </div>
        )}
      </Draggable>
    );
  };

  const renderDroppable = (provided, renderedCards) => {
    const Component = orientation === "vertical" ? VirtuosoGrid : Virtuoso;
    const FinalComponent = collapsed ? "div" : Component;
    const commonProps = {
      data: renderedCards,
      customScrollParent: laneRef.current
    };

    const verticalProps = {
      ...commonProps,
      listClassName: "grid-container",
      itemClassName: "grid-item",
      components: {
        List: ListComponent,
        Item: ItemComponent
      },
      itemContent: (index, item) => <ItemWrapper>{renderDraggable(index, item)}</ItemWrapper>,
      overscan: { main: 10, reverse: 10 },
      style: renderedCards.length === 0 ? { minHeight: "5px" } : {}
    };

    const horizontalProps = {
      ...commonProps,
      components: { Item: HeightPreservingItem },
      overscan: { main: 3, reverse: 3 },
      itemContent: (index, item) => renderDraggable(index, item),
      style: {
        minWidth: maxCardWidth,
        minHeight: maxLaneHeight
      }
    };

    const componentProps = orientation === "vertical" ? verticalProps : horizontalProps;

    const finalComponentProps = collapsed
      ? orientation === "horizontal"
        ? {
            style: {
              height: maxLaneHeight
            }
          }
        : {}
      : componentProps;

    const shouldRenderPlaceholder = orientation === "vertical" ? collapsed || renderedCards.length === 0 : collapsed;

    return (
      <HeightMemoryWrapper
        itemKey={objectHash({
          id,
          orientation,
          cardSettings,
          cardLength: renderedCards?.length
        })}
        maxHeight={maxLaneHeight}
        setMaxHeight={setMaxLaneHeight}
        override={orientation !== "horizontal" && (collapsed || !renderedCards.length)}
      >
        <div
          ref={laneRef}
          style={{ height: "100%", width: "100%" }}
          className={`react-trello-lane ${collapsed ? "lane-collapsed" : ""}`}
        >
          <div {...provided.droppableProps} ref={provided.innerRef} style={{ ...provided.droppableProps.style }}>
            <FinalComponent {...finalComponentProps} />
            {shouldRenderPlaceholder && provided.placeholder}
          </div>
        </div>
      </HeightMemoryWrapper>
    );
  };

  const renderDragContainer = () => (
    <Droppable
      droppableId={id}
      index={index}
      type="lane"
      direction={orientation === "horizontal" ? "vertical" : "grid"}
      mode="virtual"
      renderClone={(provided, snapshot, rubric) => {
        const card = sortedCards[rubric.source.index];
        return (
          <div
            {...provided.draggableProps}
            {...provided.dragHandleProps}
            ref={provided.innerRef}
            style={{
              ...provided.draggableProps.style,
              minHeight: maxCardHeight,
              minWidth: maxCardWidth
            }}
            className={`clone ${snapshot.isDragging ? "is-dragging" : ""}`}
            key={card.id}
          >
            <ProductionBoardCard
              technician={technician}
              bodyshop={bodyshop}
              cardSettings={cardSettings}
              key={card.id}
              className="react-trello-card"
              card={card}
              clone={false}
            />
          </div>
        );
      }}
    >
      {(provided) => renderDroppable(provided, sortedCards)}
    </Droppable>
  );

  return (
    <Section key={`lane-${id}-${lastDrag}`} orientation={orientation} cardSettings={cardSettings}>
      <div onDoubleClick={toggleLaneCollapsed} className="react-trello-column-header">
        <span className="lane-title">
          {collapsed ? <EyeInvisibleOutlined className="icon" /> : <EyeOutlined className="icon" />}
          {title}
        </span>
      </div>
      {renderDragContainer()}
      <LaneFooter onClick={toggleLaneCollapsed} collapsed={collapsed} />
    </Section>
  );
};

Lane.propTypes = {
  id: PropTypes.string.isRequired,
  title: PropTypes.node.isRequired,
  index: PropTypes.number.isRequired,
  laneSortFunction: PropTypes.func,
  cards: PropTypes.array.isRequired,
  orientation: PropTypes.string.isRequired,
  isProcessing: PropTypes.bool.isRequired,
  cardSettings: PropTypes.object.isRequired,
  maxLaneHeight: PropTypes.number.isRequired,
  setMaxLaneHeight: PropTypes.func.isRequired,
  maxCardHeight: PropTypes.number.isRequired,
  setMaxCardHeight: PropTypes.func.isRequired,
  maxCardWidth: PropTypes.number.isRequired,
  setMaxCardWidth: PropTypes.func.isRequired,
  lastDrag: PropTypes.number
};

const mapDispatchToProps = (dispatch) => ({
  actions: bindActionCreators(actions, dispatch)
});

const mapStateToProps = createStructuredSelector({
  bodyshop: selectBodyshop,
  technician: selectTechnician
});

export default connect(mapStateToProps, mapDispatchToProps)(Lane);
