import { useQuery } from "@apollo/client/react";
import { Col, Row } from "antd";
import _ from "lodash";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import dayjs from "../../utils/day";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
import ScoreboardTimeTicketsChart from "./scoreboard-timetickets.chart.component";
import ScoreboardTicketsStats from "./scoreboard-timetickets.stats.component";
import ScoreboardTimeticketsTargetsTable from "./scoreboard-timetickets.targets-table.component";

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

const mapDispatchToProps = () => ({
  //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(ScoreboardTimeTicketsStats);

export function ScoreboardTimeTicketsStats({ bodyshop }) {
  const { t } = useTranslation();
  const startDate = dayjs().startOf("month");
  const endDate = dayjs().endOf("month");

  const fixedPeriods = useMemo(() => {
    const endOfThisMonth = dayjs().endOf("month");
    const startofthisMonth = dayjs().startOf("month");

    const endOfLastmonth = dayjs().subtract(1, "month").endOf("month");
    const startOfLastmonth = dayjs().subtract(1, "month").startOf("month");

    const endOfThisWeek = dayjs().endOf("week");
    const startOfThisWeek = dayjs().startOf("week");

    const endOfLastWeek = dayjs().subtract(1, "week").endOf("week");
    const startOfLastWeek = dayjs().subtract(1, "week").startOf("week");

    const endOfPriorWeek = dayjs().subtract(2, "week").endOf("week");
    const startOfPriorWeek = dayjs().subtract(2, "week").startOf("week");

    const allDates = [
      endOfThisMonth,
      startofthisMonth,
      endOfLastmonth,
      startOfLastmonth,
      endOfThisWeek,
      startOfThisWeek,
      endOfLastWeek,
      startOfLastWeek,
      endOfPriorWeek,
      startOfPriorWeek
    ];
    const start = dayjs.min(allDates);
    const end = dayjs.max(allDates);
    return {
      start,
      end,
      endOfThisMonth,
      startofthisMonth,
      endOfLastmonth,
      startOfLastmonth,
      endOfThisWeek,
      startOfThisWeek,
      endOfLastWeek,
      startOfLastWeek,
      endOfPriorWeek,
      startOfPriorWeek
    };
  }, []);

  const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE_SB, {
    variables: {
      start: startDate.format("YYYY-MM-DD"),
      end: endDate.format("YYYY-MM-DD"),
      fixedStart: fixedPeriods.start.format("YYYY-MM-DD"),
      fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"),
      jobStart: startDate,
      jobEnd: endDate
    },
    fetchPolicy: "network-only",
    nextFetchPolicy: "network-only",
    pollInterval: 60000 * 5,
    skip: !fixedPeriods
  });

  const calculatedData = useMemo(() => {
    if (!data) return [];
    const ret = {
      totalThisWeek: 0,
      totalThisWeekLAB: 0,
      totalThisWeekLAR: 0,
      totalLastWeek: 0,
      totalLastWeekLAB: 0,
      totalLastWeekLAR: 0,
      totalPriorWeek: 0,
      totalPriorWeekLAB: 0,
      totalPriorWeekLAR: 0,
      totalThisMonth: 0,
      totalThisMonthLAB: 0,
      totalThisMonthLAR: 0,
      totalLastMonth: 0,
      totalLastMonthLAB: 0,
      totalLastMonthLAR: 0,
      actualTotalOverPeriod: 0,
      actualTotalOverPeriodLAB: 0,
      actualTotalOverPeriodLAR: 0,
      totalEffieciencyOverPeriod: 0,
      totalEffieciencyOverPeriodLAB: 0,
      totalEffieciencyOverPeriodLAR: 0,
      seperatedThisWeek: {
        sunday: {
          total: 0,
          lab: 0,
          lar: 0
        },
        monday: {
          total: 0,
          lab: 0,
          lar: 0
        },
        tuesday: {
          total: 0,
          lab: 0,
          lar: 0
        },
        wednesday: {
          total: 0,
          lab: 0,
          lar: 0
        },
        thursday: {
          total: 0,
          lab: 0,
          lar: 0
        },
        friday: {
          total: 0,
          lab: 0,
          lar: 0
        },
        saturday: {
          total: 0,
          lab: 0,
          lar: 0
        }
      }
    };

    data.fixedperiod.forEach((ticket) => {
      const ticketDate = dayjs(ticket.date);
      if (ticketDate.isBetween(fixedPeriods.startOfThisWeek, fixedPeriods.endOfThisWeek, undefined, "[]")) {
        ret.totalThisWeek = ret.totalThisWeek + ticket.productivehrs;
        if (ticket.ciecacode !== "LAR") ret.totalThisWeekLAB = ret.totalThisWeekLAB + ticket.productivehrs;
        if (ticket.ciecacode === "LAR") ret.totalThisWeekLAR = ret.totalThisWeekLAR + ticket.productivehrs;

        //Seperate out to Day of Week
        ret.seperatedThisWeek[dayjs(ticket.date).format("dddd").toLowerCase()].total =
          ret.seperatedThisWeek[dayjs(ticket.date).format("dddd").toLowerCase()].total + ticket.productivehrs;
        if (ticket.ciecacode !== "LAR")
          ret.seperatedThisWeek[dayjs(ticket.date).format("dddd").toLowerCase()].lab =
            ret.seperatedThisWeek[dayjs(ticket.date).format("dddd").toLowerCase()].lab + ticket.productivehrs;
        if (ticket.ciecacode === "LAR")
          ret.seperatedThisWeek[dayjs(ticket.date).format("dddd").toLowerCase()].lar =
            ret.seperatedThisWeek[dayjs(ticket.date).format("dddd").toLowerCase()].lar + ticket.productivehrs;
      } else if (ticketDate.isBetween(fixedPeriods.startOfLastWeek, fixedPeriods.endOfLastWeek, undefined, "[]")) {
        ret.totalLastWeek = ret.totalLastWeek + ticket.productivehrs;
        if (ticket.ciecacode !== "LAR") ret.totalLastWeekLAB = ret.totalLastWeekLAB + ticket.productivehrs;
        if (ticket.ciecacode === "LAR") ret.totalLastWeekLAR = ret.totalLastWeekLAR + ticket.productivehrs;
      } else if (ticketDate.isBetween(fixedPeriods.startOfPriorWeek, fixedPeriods.endOfPriorWeek, undefined, "[]")) {
        ret.totalPriorWeek = ret.totalPriorWeek + ticket.productivehrs;
        if (ticket.ciecacode !== "LAR") ret.totalPriorWeekLAB = ret.totalPriorWeekLAB + ticket.productivehrs;
        if (ticket.ciecacode === "LAR") ret.totalPriorWeekLAR = ret.totalPriorWeekLAR + ticket.productivehrs;
      }
      if (ticketDate.isBetween(fixedPeriods.startofthisMonth, fixedPeriods.endOfThisMonth, undefined, "[]")) {
        ret.totalThisMonth = ret.totalThisMonth + ticket.productivehrs;
        ret.actualTotalOverPeriod = ret.actualTotalOverPeriod + (ticket.actualhrs || 0);
        if (ticket.ciecacode !== "LAR") {
          ret.totalThisMonthLAB = ret.totalThisMonthLAB + ticket.productivehrs;
          ret.actualTotalOverPeriodLAB = ret.actualTotalOverPeriodLAB + (ticket.actualhrs || 0);
        }
        if (ticket.ciecacode === "LAR") {
          ret.totalThisMonthLAR = ret.totalThisMonthLAR + ticket.productivehrs;
          ret.actualTotalOverPeriodLAR = ret.actualTotalOverPeriodLAR + (ticket.actualhrs || 0);
        }
      } else if (ticketDate.isBetween(fixedPeriods.startOfLastmonth, fixedPeriods.endOfLastmonth, undefined, "[]")) {
        ret.totalLastMonth = ret.totalLastMonth + ticket.productivehrs;
        if (ticket.ciecacode !== "LAR") ret.totalLastMonthLAB = ret.totalLastMonthLAB + ticket.productivehrs;
        if (ticket.ciecacode === "LAR") ret.totalLastMonthLAR = ret.totalLastMonthLAR + ticket.productivehrs;
      }
    });

    ret.totalEffieciencyOverPeriod = ret.actualTotalOverPeriod
      ? (ret.totalThisMonth / ret.actualTotalOverPeriod) * 100
      : 0;
    ret.totalEffieciencyOverPeriodLAB = ret.actualTotalOverPeriodLAB
      ? (ret.totalThisMonthLAB / ret.actualTotalOverPeriodLAB) * 100
      : 0;
    ret.totalEffieciencyOverPeriodLAR = ret.actualTotalOverPeriodLAR
      ? (ret.totalThisMonthLAR / ret.actualTotalOverPeriodLAR) * 100
      : 0;

    roundObject(ret);

    const ticketsGroupedByDate = _.groupBy(data.timetickets, "date");

    const listOfDays = Utils.ListOfDaysInCurrentMonth();

    const combinedData = [],
      labData = [],
      larData = [];
    var acc_comb = 0;
    var acc_lab = 0;
    var acc_lar = 0;

    listOfDays.forEach((day) => {
      const r = {
        date: dayjs(day).format("MM/DD"),
        actualhrs: 0,
        productivehrs: 0
      };

      const combined = {
        accTargetHrs: _.round(
          Utils.AsOfDateTargetHours(
            bodyshop.scoreboard_target.dailyBodyTarget + bodyshop.scoreboard_target.dailyPaintTarget,
            day
          ) +
            (bodyshop.scoreboard_target.dailyBodyTarget + bodyshop.scoreboard_target.dailyPaintTarget),
          1
        ),
        accHrs: 0
      };
      const lab = {
        accTargetHrs: _.round(
          Utils.AsOfDateTargetHours(bodyshop.scoreboard_target.dailyBodyTarget, day) +
            bodyshop.scoreboard_target.dailyBodyTarget,
          1
        ),
        accHrs: 0
      };
      const lar = {
        accTargetHrs: _.round(
          Utils.AsOfDateTargetHours(bodyshop.scoreboard_target.dailyPaintTarget, day) +
            bodyshop.scoreboard_target.dailyPaintTarget,
          1
        ),
        accHrs: 0
      };

      if (ticketsGroupedByDate[day]) {
        ticketsGroupedByDate[day].forEach((ticket) => {
          r.actualhrs = r.actualhrs + ticket.actualhrs;
          r.productivehrs = r.productivehrs + ticket.productivehrs;
          acc_comb = acc_comb + ticket.productivehrs;

          if (ticket.ciecacode !== "LAR") acc_lab = acc_lab + ticket.productivehrs;
          if (ticket.ciecacode === "LAR") acc_lar = acc_lar + ticket.productivehrs;
        });
      }
      combined.accHrs = acc_comb;
      lab.accHrs = acc_lab;
      lar.accHrs = acc_lar;

      combinedData.push({ ...r, ...combined });
      labData.push({ ...r, ...lab });
      larData.push({ ...r, ...lar });
    });

    const jobData = {};

    const dataJobs = data.jobs.map((job) => ({
      ...job,
      tthrs: job.joblines.reduce((acc, val) => acc + val.mod_lb_hrs, 0)
    }));

    jobData.tthrs = dataJobs.reduce((acc, val) => acc + val.tthrs, 0).toFixed(1);

    jobData.count = dataJobs.length.toFixed(0);

    return {
      fixed: ret,
      combinedData: combinedData,
      labData: labData,
      larData: larData,
      jobData: jobData
    };
  }, [fixedPeriods, data, bodyshop]);

  if (error) return <AlertComponent title={error.message} type="error" />;
  if (loading) return <LoadingSpinner />;
  return (
    <Row gutter={[16, 16]}>
      <Col span={24}>
        <ScoreboardTimeticketsTargetsTable />
      </Col>
      <Col span={24}>
        <ScoreboardTicketsStats data={calculatedData.fixed} jobData={calculatedData.jobData} />
      </Col>
      <Col span={24}>
        <ScoreboardTimeTicketsChart
          data={calculatedData.combinedData}
          chartTitle={t("scoreboard.labels.combinedcharttitle")}
        />
      </Col>
      <Col span={12}>
        <ScoreboardTimeTicketsChart data={calculatedData.labData} chartTitle={t("scoreboard.labels.bodycharttitle")} />
      </Col>
      <Col span={12}>
        <ScoreboardTimeTicketsChart
          data={calculatedData.larData}
          chartTitle={t("scoreboard.labels.refinishcharttitle")}
        />
      </Col>
    </Row>
  );
}

function roundObject(inputObj) {
  for (var key of Object.keys(inputObj)) {
    if (typeof inputObj[key] === "number") {
      inputObj[key] = inputObj[key].toFixed(1);
    } else if (Array.isArray(inputObj[key])) {
      inputObj[key].forEach((item) => roundObject(item));
    } else if (typeof inputObj[key] === "object") {
      roundObject(inputObj[key]);
    }
  }
}
