import { SyncOutlined } from "@ant-design/icons";
import { useApolloClient } from "@apollo/client";
import Board from "./trello-board/index";
import { Button, notification, Skeleton, Space, Statistic } from "antd";
import { PageHeader } from "@ant-design/pro-layout";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component";
import CardColorLegend from "../production-board-kanban-card/production-board-kanban-card-color-legend.component";
import "./production-board-kanban.styles.scss";
import { createBoardData } from "./production-board-kanban.utils.js";
import ProductionBoardKanbanSettings from "./production-board-kanban.settings.component.jsx";
import cloneDeep from "lodash/cloneDeep";
import isEqual from "lodash/isEqual";

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

const mapDispatchToProps = (dispatch) => ({
  insertAuditTrail: ({ jobid, operation, type }) =>
    dispatch(
      insertAuditTrail({
        jobid,
        operation,
        type
      })
    )
});

export function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTrail, associationSettings }) {
  const [boardLanes, setBoardLanes] = useState({ lanes: [] });
  const [filter, setFilter] = useState({ search: "", employeeId: null });
  const [loading, setLoading] = useState(true);
  const [isMoving, setIsMoving] = useState(false);
  const [orientation, setOrientation] = useState("vertical");

  const { t } = useTranslation();

  useEffect(() => {
    if (associationSettings) {
      setLoading(false);
      setOrientation(associationSettings?.kanban_settings?.orientation ? "vertical" : "horizontal");
    }
  }, [associationSettings]);

  useEffect(() => {
    const newBoardData = createBoardData(
      [...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])],
      data,
      filter
    );

    newBoardData.lanes = newBoardData.lanes.map((lane) => ({
      ...lane,
      title: `${lane.title} (${lane.cards.length})`
    }));

    setBoardLanes((prevBoardLanes) => {
      const deepClonedData = cloneDeep(newBoardData);
      if (!isEqual(prevBoardLanes, deepClonedData)) {
        return deepClonedData;
      }
      return prevBoardLanes;
    });
    setIsMoving(false);
  }, [data, bodyshop.md_ro_statuses, filter]);

  const client = useApolloClient();

  const getCardByID = useCallback((data, cardId) => {
    for (const lane of data.lanes) {
      for (const card of lane.cards) {
        if (card.id === cardId) {
          return card;
        }
      }
    }
    return null;
  }, []);

  const onDragEnd = useCallback(
    async ({ type, source, destination, draggableId }) => {
      logImEXEvent("kanban_drag_end");

      if (!type || type !== "lane" || !source || !destination || isMoving) return;

      setIsMoving(true);

      const targetLane = boardLanes.lanes.find((lane) => lane.id === destination.droppableId);
      const sourceLane = boardLanes.lanes.find((lane) => lane.id === source.droppableId);

      const sameColumnTransfer = source.droppableId === destination.droppableId;
      const sourceCard = getCardByID(boardLanes, draggableId);

      const movedCardWillBeFirst = destination.index === 0;
      const movedCardWillBeLast = destination.index > targetLane.cards.length - 1;

      const lastCardInTargetLane = targetLane.cards[targetLane.cards.length - 1];

      const oldChildCard = sourceLane.cards[destination.index + 1];

      const newChildCard = movedCardWillBeLast
        ? null
        : targetLane.cards[
            sameColumnTransfer
              ? destination.index - destination.index > 0
                ? destination.index
                : destination.index + 1
              : destination.index
          ];

      const oldChildCardNewParent = oldChildCard ? sourceCard.metadata.kanbanparent : null;

      let movedCardNewKanbanParent;
      if (movedCardWillBeFirst) {
        movedCardNewKanbanParent = "-1";
      } else if (movedCardWillBeLast) {
        movedCardNewKanbanParent = lastCardInTargetLane.id;
      } else if (!!newChildCard) {
        movedCardNewKanbanParent = newChildCard.metadata.kanbanparent;
      } else {
        console.log("==> !!!!!!Couldn't find a parent.!!!! <==");
      }
      const newChildCardNewParent = newChildCard ? draggableId : null;
      try {
        const update = await client.mutate({
          mutation: generate_UPDATE_JOB_KANBAN(
            oldChildCard ? oldChildCard.id : null,
            oldChildCardNewParent,
            draggableId,
            movedCardNewKanbanParent,
            targetLane.id,
            newChildCard ? newChildCard.id : null,
            newChildCardNewParent
          )
        });

        insertAuditTrail({
          jobid: draggableId,
          operation: AuditTrailMapping.jobstatuschange(targetLane.id),
          type: "jobstatuschange"
        });

        if (update.errors) {
          notification["error"]({
            message: t("production.errors.boardupdate", {
              message: JSON.stringify(update.errors)
            })
          });
        }
      } catch (error) {
        notification["error"]({
          message: t("production.errors.boardupdate", {
            message: error.message
          })
        });
      } finally {
        setIsMoving(false);
      }
    },
    [boardLanes, client, getCardByID, insertAuditTrail, isMoving, t]
  );

  const totalHrs = useMemo(
    () =>
      data
        .reduce(
          (acc, val) =>
            acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0) + (val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0),
          0
        )
        .toFixed(1),
    [data]
  );

  const totalLAB = useMemo(
    () => data.reduce((acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0).toFixed(1),
    [data]
  );

  const totalLAR = useMemo(
    () => data.reduce((acc, val) => acc + (val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0).toFixed(1),
    [data]
  );

  const cardSettings = useMemo(
    () =>
      associationSettings?.kanban_settings && Object.keys(associationSettings.kanban_settings).length > 0
        ? associationSettings.kanban_settings
        : {
            ats: true,
            clm_no: true,
            compact: false,
            ownr_nm: true,
            sublets: true,
            ins_co_nm: true,
            production_note: true,
            employeeassignments: true,
            scheduled_completion: true,
            cardcolor: false,
            orientation: false
          },
    [associationSettings]
  );

  const handleSettingsChange = (newSettings) => {
    setOrientation(newSettings.orientation ? "vertical" : "horizontal");
  };

  if (loading) {
    return <Skeleton active />;
  }

  return (
    <div>
      <IndefiniteLoading loading={isMoving} />
      <PageHeader
        title={
          <Space>
            <Statistic title={t("dashboard.titles.productionhours")} value={totalHrs} />
            <Statistic title={t("dashboard.titles.labhours")} value={totalLAB} />
            <Statistic title={t("dashboard.titles.larhours")} value={totalLAR} />
            <Statistic title={t("appointments.labels.inproduction")} value={data && data.length} />
          </Space>
        }
        extra={
          <Space wrap>
            <Button onClick={() => refetch && refetch()}>
              <SyncOutlined />
            </Button>
            <ProductionBoardFilters filter={filter} setFilter={setFilter} loading={isMoving} />
            <ProductionBoardKanbanSettings
              parentLoading={setLoading}
              associationSettings={associationSettings}
              onSettingsChange={handleSettingsChange}
            />
          </Space>
        }
      />
      {cardSettings.cardcolor && <CardColorLegend cardSettings={cardSettings} bodyshop={bodyshop} />}
      <ProductionListDetailComponent jobs={data} />
      <Board data={boardLanes} onDragEnd={onDragEnd} orientation={orientation} cardSettings={cardSettings} />
    </div>
  );
}

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