import { useCallback, useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { DragDropContext } from "../dnd/lib";
import PropTypes from "prop-types";
import isEqual from "lodash/isEqual";
import Lane from "./Lane";
import { PopoverWrapper } from "react-popopo";
import * as actions from "../../../../redux/trello/trello.actions.js";
import { BoardWrapper } from "../styles/Base.js";
import ProductionStatistics from "../../production-board-kanban.statistics.jsx";

const useDragMap = () => {
  const dragMapRef = useRef(new Map());

  const setDragTime = (laneId) => {
    dragMapRef.current.set(laneId, Date.now());
  };

  const getLastDragTime = (laneId) => {
    return dragMapRef.current.get(laneId);
  };

  return { setDragTime, getLastDragTime };
};

const BoardContainer = ({
  data,
  onDataChange = () => {
    // NO OP
  },
  onDragEnd = () => {
    // NO OP
  },
  laneSortFunction = () => {
    // NO OP
  },
  orientation = "horizontal",
  cardSettings = {},
  eventBusHandle,
  reducerData,
  queryData
}) => {
  const [isDragging, setIsDragging] = useState(false);
  const [isProcessing, setIsProcessing] = useState(false);
  const [maxLaneHeight, setMaxLaneHeight] = useState(0);
  const [maxCardHeight, setMaxCardHeight] = useState(0);
  const [maxCardWidth, setMaxCardWidth] = useState(0);

  const dispatch = useDispatch();
  const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
  const { setDragTime, getLastDragTime } = useDragMap();

  const wireEventBus = useCallback(() => {
    const eventBus = {
      publish: (event) => {
        switch (event.type) {
          // case "ADD_CARD":
          //   return dispatch(actions.addCard({ laneId: event.laneId, card: event.card }));
          // case "REMOVE_CARD":
          //   return dispatch(actions.removeCard({ laneId: event.laneId, cardId: event.cardId }));
          // case "REFRESH_BOARD":
          //   return dispatch(actions.loadBoard(event.data));
          // case "UPDATE_CARDS":
          //   return dispatch(actions.updateCards({ laneId: event.laneId, cards: event.cards }));
          // case "UPDATE_CARD":
          //   return dispatch(actions.updateCard({ laneId: event.laneId, updatedCard: event.card }));
          // case "UPDATE_LANES":
          //   return dispatch(actions.updateLanes(event.lanes));
          // case "UPDATE_LANE":
          //   return dispatch(actions.updateLane(event.lane));
          case "MOVE_CARD":
            return dispatch(
              actions.moveCardAcrossLanes({
                fromLaneId: event.fromLaneId,
                toLaneId: event.toLaneId,
                cardId: event.cardId,
                index: event.index,
                event
              })
            );
          default:
            return;
        }
      }
    };
    eventBusHandle(eventBus);
  }, [dispatch, eventBusHandle]);

  useEffect(() => {
    dispatch(actions.loadBoard(data));
    if (eventBusHandle) {
      wireEventBus();
    }
  }, [data, eventBusHandle, dispatch, wireEventBus]);

  useEffect(() => {
    if (!isEqual(currentReducerData, reducerData)) {
      onDataChange(currentReducerData);
    }
  }, [currentReducerData, reducerData, onDataChange]);

  const onDragStart = useCallback(() => {
    setIsDragging(true);
  }, []);

  const onLaneDrag = useCallback(
    async ({ draggableId, type, source, reason, mode, destination, combine }) => {
      setIsDragging(false);

      // Validate drag type and source
      if (type !== "lane" || !source) {
        // Invalid drag type or missing source, attempt to revert if possible
        if (source) {
          dispatch(
            actions.moveCardAcrossLanes({
              fromLaneId: source.droppableId,
              toLaneId: source.droppableId,
              cardId: draggableId,
              index: source.index
            })
          );
        }
        setIsProcessing(false);
        try {
          await onDragEnd({ draggableId, type, source, reason, mode, destination, combine });
        } catch (err) {
          console.error("Error in onLaneDrag for invalid drag type or source", err);
        }
        return;
      }

      setDragTime(source.droppableId);
      setIsProcessing(true);

      // Handle valid drop to a different lane or position
      if (destination && !isEqual(source, destination)) {
        dispatch(
          actions.moveCardAcrossLanes({
            fromLaneId: source.droppableId,
            toLaneId: destination.droppableId,
            cardId: draggableId,
            index: destination.index
          })
        );
      } else {
        // Same-lane drop or no destination, revert to original position
        dispatch(
          actions.moveCardAcrossLanes({
            fromLaneId: source.droppableId,
            toLaneId: source.droppableId,
            cardId: draggableId,
            index: source.index
          })
        );
      }

      try {
        await onDragEnd({ draggableId, type, source, reason, mode, destination, combine });
      } catch (err) {
        console.error("Error in onLaneDrag", err);
        // Ensure revert on error
        dispatch(
          actions.moveCardAcrossLanes({
            fromLaneId: source.droppableId,
            toLaneId: source.droppableId,
            cardId: draggableId,
            index: source.index
          })
        );
      } finally {
        setIsProcessing(false);
      }
    },
    [dispatch, onDragEnd, setDragTime]
  );

  return (
    <div>
      <ProductionStatistics data={queryData} reducerData={currentReducerData} cardSettings={cardSettings} />
      <PopoverWrapper>
        <BoardWrapper orientation={orientation}>
          <DragDropContext onDragEnd={onLaneDrag} onDragStart={onDragStart} contextId="production-board">
            {currentReducerData.lanes.map((lane, index) => (
              <Lane
                key={lane.id}
                id={lane.id}
                title={lane.title}
                index={index}
                laneSortFunction={laneSortFunction}
                orientation={orientation}
                cards={lane.cards}
                isDragging={isDragging}
                isProcessing={isProcessing}
                cardSettings={cardSettings}
                maxLaneHeight={maxLaneHeight}
                setMaxLaneHeight={setMaxLaneHeight}
                maxCardHeight={maxCardHeight}
                setMaxCardHeight={setMaxCardHeight}
                maxCardWidth={maxCardWidth}
                setMaxCardWidth={setMaxCardWidth}
                lastDrag={getLastDragTime(lane.id)}
              />
            ))}
          </DragDropContext>
        </BoardWrapper>
      </PopoverWrapper>
    </div>
  );
};

BoardContainer.propTypes = {
  id: PropTypes.string,
  data: PropTypes.object.isRequired,
  reducerData: PropTypes.object,
  onDataChange: PropTypes.func,
  eventBusHandle: PropTypes.func,
  laneSortFunction: PropTypes.func,
  handleDragEnd: PropTypes.func,
  orientation: PropTypes.string
};

export default BoardContainer;
