import { useMemo } from "react";
import { Card, Statistic } from "antd";
import { useTranslation } from "react-i18next";
import PropTypes from "prop-types";
import { defaultKanbanSettings, statisticsItems } from "./settings/defaultKanbanSettings.js";
import Dinero from "dinero.js";

export const StatisticType = {
  HOURS: "hours",
  AMOUNT: "amount",
  JOBS: "jobs",
  TASKS: "tasks"
};

const mergeStatistics = (items, values) => {
  const valuesMap = values.reduce((acc, value) => {
    acc[value.id] = value;
    return acc;
  }, {});

  return items.map((item) => ({
    ...item,
    value: valuesMap[item.id]?.value,
    type: valuesMap[item.id]?.type
  }));
};

const ProductionStatistics = ({ data, cardSettings, reducerData }) => {
  const { t } = useTranslation();

  const calculateTotal = (items, key, subKey) => {
    return items.reduce((acc, item) => acc + (item[key]?.aggregate?.sum?.[subKey] || 0), 0);
  };

  const calculateTotalAmount = (items, key) => {
    return items.reduce((acc, item) => acc.add(Dinero(item[key]?.totals?.subtotal ?? Dinero())), Dinero({ amount: 0 }));
  };

  const calculateReducerTotalAmount = (lanes, key) => {
    return lanes.reduce(
      (acc, lane) => {
        return acc.add(
          lane.cards.reduce(
            (laneAcc, card) => laneAcc.add(Dinero(card.metadata[key]?.totals?.subtotal ?? Dinero())),
            Dinero({ amount: 0 })
          )
        );
      },
      Dinero({ amount: 0 })
    );
  };

  const calculateReducerTotal = (lanes, key, subKey) => {
    return lanes.reduce((acc, lane) => {
      return (
        acc + lane.cards.reduce((laneAcc, card) => laneAcc + (card.metadata[key]?.aggregate?.sum?.[subKey] || 0), 0)
      );
    }, 0);
  };

  const formatValue = (value, type) => {
    if (type === StatisticType.JOBS) {
      return value.toFixed(0);
    }
    if (type === StatisticType.HOURS) {
      return value.toFixed(2);
    }
    return value;
  };

  const totalHrs = useMemo(() => {
    if (!cardSettings.totalHrs) return null;
    const total = calculateTotal(data, "labhrs", "mod_lb_hrs") + calculateTotal(data, "larhrs", "mod_lb_hrs");
    return parseFloat(total.toFixed(2));
  }, [data, cardSettings.totalHrs]);

  const totalLAB = useMemo(() => {
    if (!cardSettings.totalLAB) return null;
    const total = calculateTotal(data, "labhrs", "mod_lb_hrs");
    return parseFloat(total.toFixed(2));
  }, [data, cardSettings.totalLAB]);

  const totalLAR = useMemo(() => {
    if (!cardSettings.totalLAR) return null;
    const total = calculateTotal(data, "larhrs", "mod_lb_hrs");
    return parseFloat(total.toFixed(2));
  }, [data, cardSettings.totalLAR]);

  const jobsInProduction = useMemo(
    () => (cardSettings.jobsInProduction ? data.length : null),
    [data, cardSettings.jobsInProduction]
  );

  const totalAmountInProduction = useMemo(() => {
    if (!cardSettings.totalAmountInProduction) return null;
    const total = calculateTotalAmount(data, "job_totals");
    return total.toFormat("$0,0.00");
  }, [data, cardSettings.totalAmountInProduction]);

  const totalAmountOnBoard = useMemo(() => {
    if (!reducerData || !cardSettings.totalAmountOnBoard) return null;
    const total = calculateReducerTotalAmount(reducerData.lanes, "job_totals");
    return total.toFormat("$0,0.00");
  }, [reducerData, cardSettings.totalAmountOnBoard]);

  const totalHrsOnBoard = useMemo(() => {
    if (!reducerData || !cardSettings.totalHrsOnBoard) return null;
    const total =
      calculateReducerTotal(reducerData.lanes, "labhrs", "mod_lb_hrs") +
      calculateReducerTotal(reducerData.lanes, "larhrs", "mod_lb_hrs");
    return parseFloat(total.toFixed(2));
  }, [reducerData, cardSettings.totalHrsOnBoard]);

  const totalLABOnBoard = useMemo(() => {
    if (!reducerData || !cardSettings.totalLABOnBoard) return null;
    const total = calculateReducerTotal(reducerData.lanes, "labhrs", "mod_lb_hrs");
    return parseFloat(total.toFixed(2));
  }, [reducerData, cardSettings.totalLABOnBoard]);

  const totalLAROnBoard = useMemo(() => {
    if (!reducerData || !cardSettings.totalLAROnBoard) return null;
    const total = calculateReducerTotal(reducerData.lanes, "larhrs", "mod_lb_hrs");
    return parseFloat(total.toFixed(2));
  }, [reducerData, cardSettings.totalLAROnBoard]);

  const jobsOnBoard = useMemo(
    () =>
      reducerData && cardSettings.jobsOnBoard
        ? reducerData.lanes.reduce((acc, lane) => acc + lane.cards.length, 0)
        : null,
    [reducerData, cardSettings.jobsOnBoard]
  );

  const tasksInProduction = useMemo(() => {
    if (!data || !cardSettings.tasksInProduction) return null;
    return data.reduce((acc, item) => acc + (item.tasks_aggregate?.aggregate?.count || 0), 0);
  }, [data, cardSettings.tasksInProduction]);

  const tasksOnBoard = useMemo(() => {
    if (!reducerData || !cardSettings.tasksOnBoard) return null;
    return reducerData.lanes.reduce((acc, lane) => {
      return (
        acc + lane.cards.reduce((laneAcc, card) => laneAcc + (card.metadata.tasks_aggregate?.aggregate?.count || 0), 0)
      );
    }, 0);
  }, [reducerData, cardSettings.tasksOnBoard]);

  const statistics = useMemo(
    () =>
      mergeStatistics(statisticsItems, [
        { id: 0, value: totalHrs, type: StatisticType.HOURS },
        { id: 1, value: totalAmountInProduction, type: StatisticType.AMOUNT },
        { id: 2, value: totalLAB, type: StatisticType.HOURS },
        { id: 3, value: totalLAR, type: StatisticType.HOURS },
        { id: 4, value: jobsInProduction, type: StatisticType.JOBS },
        { id: 5, value: totalHrsOnBoard, type: StatisticType.HOURS },
        { id: 6, value: totalAmountOnBoard, type: StatisticType.AMOUNT },
        { id: 7, value: totalLABOnBoard, type: StatisticType.HOURS },
        { id: 8, value: totalLAROnBoard, type: StatisticType.HOURS },
        { id: 9, value: jobsOnBoard, type: StatisticType.JOBS },
        { id: 10, value: tasksOnBoard, type: StatisticType.TASKS },
        { id: 11, value: tasksInProduction, type: StatisticType.TASKS }
      ]),
    [
      totalHrs,
      totalAmountInProduction,
      totalLAB,
      totalLAR,
      jobsInProduction,
      totalHrsOnBoard,
      totalAmountOnBoard,
      totalLABOnBoard,
      totalLAROnBoard,
      jobsOnBoard,
      tasksOnBoard,
      tasksInProduction
    ]
  );

  const sortedStatistics = useMemo(() => {
    const statisticsMap = new Map(statistics.map((stat) => [stat.id, stat]));

    return (
      cardSettings?.statisticsOrder ? cardSettings.statisticsOrder : defaultKanbanSettings.statisticsOrder
    ).reduce((sorted, orderId) => {
      const value = statisticsMap.get(orderId);
      if (value?.value) {
        sorted.push(value);
      }
      return sorted;
    }, []);
  }, [statistics, cardSettings.statisticsOrder]);

  return (
    <div style={{ display: "flex", gap: "5px", flexWrap: "wrap", marginBottom: "5px" }}>
      {sortedStatistics.map((stat) => (
        <Card styles={{ body: { padding: "8px" } }} key={stat.id}>
          <Statistic
            title={t(`production.statistics.${stat.label}`)}
            value={formatValue(stat.value, stat.type)}
            suffix={
              stat.type === StatisticType.HOURS
                ? t("production.statistics.hours")
                : stat.type === StatisticType.JOBS
                  ? t("production.statistics.jobs")
                  : undefined
            }
          />
        </Card>
      ))}
    </div>
  );
};

ProductionStatistics.propTypes = {
  data: PropTypes.array.isRequired,
  cardSettings: PropTypes.object.isRequired,
  reducerData: PropTypes.object
};

export default ProductionStatistics;
