import Icon, { SyncOutlined } from "@ant-design/icons";
import { gql, useMutation, useQuery } from "@apollo/client";
import { Button, Dropdown, Space } from "antd";
import { PageHeader } from "@ant-design/pro-layout";
import i18next from "i18next";
import _ from "lodash";
import dayjs from "../../utils/day";
import React, { useState } from "react";
import { Responsive, WidthProvider } from "react-grid-layout";
import { useTranslation } from "react-i18next";
import { MdClose } from "react-icons/md";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { UPDATE_DASHBOARD_LAYOUT } from "../../graphql/user.queries";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
import DashboardMonthlyEmployeeEfficiency, {
  DashboardMonthlyEmployeeEfficiencyGql
} from "../dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component";
import DashboardMonthlyJobCosting from "../dashboard-components/monthly-job-costing/monthly-job-costing.component";
import DashboardMonthlyLaborSales from "../dashboard-components/monthly-labor-sales/monthly-labor-sales.component";
import DashboardMonthlyPartsSales from "../dashboard-components/monthly-parts-sales/monthly-parts-sales.component";
import DashboardMonthlyRevenueGraph, {
  DashboardMonthlyRevenueGraphGql
} from "../dashboard-components/monthly-revenue-graph/monthly-revenue-graph.component";
import DashboardProjectedMonthlySales, {
  DashboardProjectedMonthlySalesGql
} from "../dashboard-components/pojected-monthly-sales/projected-monthly-sales.component";
import DashboardTotalProductionDollars from "../dashboard-components/total-production-dollars/total-production-dollars.component";
import DashboardTotalProductionHours, {
  DashboardTotalProductionHoursGql
} from "../dashboard-components/total-production-hours/total-production-hours.component";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
//Combination of the following:
// /node_modules/react-grid-layout/css/styles.css
// /node_modules/react-resizable/css/styles.css
import DashboardScheduledInToday, {
  DashboardScheduledInTodayGql
} from "../dashboard-components/scheduled-in-today/scheduled-in-today.component";
import DashboardScheduledOutToday, {
  DashboardScheduledOutTodayGql
} from "../dashboard-components/scheduled-out-today/scheduled-out-today.component";
import JobLifecycleDashboardComponent, {
  JobLifecycleDashboardGQL
} from "../dashboard-components/job-lifecycle/job-lifecycle-dashboard.component";
import "./dashboard-grid.styles.scss";
import { GenerateDashboardData } from "./dashboard-grid.utils";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";

const ResponsiveReactGridLayout = WidthProvider(Responsive);

const mapStateToProps = createStructuredSelector({
  currentUser: selectCurrentUser,
  bodyshop: selectBodyshop
});
const mapDispatchToProps = (dispatch) => ({
  //setUserLanguage: language => dispatch(setUserLanguage(language))
});

export function DashboardGridComponent({ currentUser, bodyshop }) {
  const { t } = useTranslation();
  const [state, setState] = useState({
    ...(bodyshop.associations[0].user.dashboardlayout
      ? bodyshop.associations[0].user.dashboardlayout
      : { items: [], layout: {}, layouts: [] })
  });
  const notification = useNotification();

  const { loading, error, data, refetch } = useQuery(createDashboardQuery(state), {
    fetchPolicy: "network-only",
    nextFetchPolicy: "network-only"
  });

  const [updateLayout] = useMutation(UPDATE_DASHBOARD_LAYOUT);

  const handleLayoutChange = async (layout, layouts) => {
    logImEXEvent("dashboard_change_layout");

    setState({ ...state, layout, layouts });

    const result = await updateLayout({
      variables: {
        email: currentUser.email,
        layout: { ...state, layout, layouts }
      }
    });
    if (!!result.errors) {
      notification["error"]({
        message: t("dashboard.errors.updatinglayout", {
          message: JSON.stringify(result.errors)
        })
      });
    }
  };
  const handleRemoveComponent = (key) => {
    logImEXEvent("dashboard_remove_component", { name: key });
    const idxToRemove = state.items.findIndex((i) => i.i === key);

    const items = _.cloneDeep(state.items);

    items.splice(idxToRemove, 1);
    setState({ ...state, items });
  };

  const handleAddComponent = (e) => {
    logImEXEvent("dashboard_add_component", { name: e });
    setState({
      ...state,
      items: [
        ...state.items,
        {
          i: e.key,
          x: (state.items.length * 2) % (state.cols || 12),
          y: 99, // puts it at the bottom
          w: componentList[e.key].w || 2,
          h: componentList[e.key].h || 2
        }
      ]
    });
  };

  const dashboarddata = React.useMemo(() => GenerateDashboardData(data), [data]);
  const existingLayoutKeys = state.items.map((i) => i.i);

  const menuItems = Object.keys(componentList).map((key) => ({
    key: key,
    label: componentList[key].label,
    value: key,
    disabled: existingLayoutKeys.includes(key)
  }));

  const menu = { items: menuItems, onClick: handleAddComponent };

  if (error) return <AlertComponent message={error.message} type="error" />;

  return (
    <div>
      <PageHeader
        extra={
          <Space>
            <Button onClick={() => refetch()}>
              <SyncOutlined />
            </Button>
            <Dropdown menu={menu} trigger={["click"]}>
              <Button>{t("dashboard.actions.addcomponent")}</Button>
            </Dropdown>
          </Space>
        }
      />

      <ResponsiveReactGridLayout
        className="layout"
        breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
        cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
        width="100%"
        layouts={state.layouts}
        onLayoutChange={handleLayoutChange}
        //   onBreakpointChange={onBreakpointChange}
      >
        {state.items.map((item, index) => {
          const TheComponent = componentList[item.i].component;
          return (
            <div
              key={item.i}
              data-grid={{
                ...item,
                minH: componentList[item.i].minH || 1,
                minW: componentList[item.i].minW || 1
              }}
            >
              <LoadingSkeleton loading={loading}>
                <Icon
                  component={MdClose}
                  key={item.i}
                  style={{
                    position: "absolute",
                    zIndex: "2",
                    right: ".25rem",
                    top: ".25rem",
                    cursor: "pointer"
                  }}
                  onClick={() => handleRemoveComponent(item.i)}
                />
                <TheComponent className="dashboard-card" bodyshop={bodyshop} data={dashboarddata} />
              </LoadingSkeleton>
            </div>
          );
        })}
      </ResponsiveReactGridLayout>
    </div>
  );
}

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

const componentList = {
  ProductionDollars: {
    label: i18next.t("dashboard.titles.productiondollars"),
    component: DashboardTotalProductionDollars,
    gqlFragment: null,
    w: 1,
    h: 1,
    minW: 2,
    minH: 1
  },
  ProductionHours: {
    label: i18next.t("dashboard.titles.productionhours"),
    component: DashboardTotalProductionHours,
    gqlFragment: DashboardTotalProductionHoursGql,
    w: 3,
    h: 1,
    minW: 3,
    minH: 1
  },
  ProjectedMonthlySales: {
    label: i18next.t("dashboard.titles.projectedmonthlysales"),
    component: DashboardProjectedMonthlySales,
    gqlFragment: DashboardProjectedMonthlySalesGql,
    w: 2,
    h: 1,
    minW: 2,
    minH: 1
  },
  MonthlyRevenueGraph: {
    label: i18next.t("dashboard.titles.monthlyrevenuegraph"),
    component: DashboardMonthlyRevenueGraph,
    gqlFragment: DashboardMonthlyRevenueGraphGql,
    w: 4,
    h: 2,
    minW: 4,
    minH: 2
  },
  MonthlyJobCosting: {
    label: i18next.t("dashboard.titles.monthlyjobcosting"),
    component: DashboardMonthlyJobCosting,
    gqlFragment: null,
    minW: 6,
    minH: 3,
    w: 6,
    h: 3
  },
  MonthlyPartsSales: {
    label: i18next.t("dashboard.titles.monthlypartssales"),
    component: DashboardMonthlyPartsSales,
    gqlFragment: null,
    minW: 2,
    minH: 2,
    w: 2,
    h: 2
  },
  MonthlyLaborSales: {
    label: i18next.t("dashboard.titles.monthlylaborsales"),
    component: DashboardMonthlyLaborSales,
    gqlFragment: null,
    minW: 2,
    minH: 2,
    w: 2,
    h: 2
  },
  // Typo in Efficency should be Efficiency, but changing it would reset users dashboard settings
  MonthlyEmployeeEfficency: {
    label: i18next.t("dashboard.titles.monthlyemployeeefficiency"),
    component: DashboardMonthlyEmployeeEfficiency,
    gqlFragment: DashboardMonthlyEmployeeEfficiencyGql,
    minW: 2,
    minH: 2,
    w: 2,
    h: 2
  },
  ScheduleInToday: {
    label: i18next.t("dashboard.titles.scheduledintoday"),
    component: DashboardScheduledInToday,
    gqlFragment: DashboardScheduledInTodayGql,
    minW: 6,
    minH: 2,
    w: 10,
    h: 3
  },
  ScheduleOutToday: {
    label: i18next.t("dashboard.titles.scheduledouttoday"),
    component: DashboardScheduledOutToday,
    gqlFragment: DashboardScheduledOutTodayGql,
    minW: 6,
    minH: 2,
    w: 10,
    h: 3
  },
  JobLifecycle: {
    label: i18next.t("dashboard.titles.joblifecycle"),
    component: JobLifecycleDashboardComponent,
    gqlFragment: JobLifecycleDashboardGQL,
    minW: 6,
    minH: 3,
    w: 6,
    h: 3
  }
};

const createDashboardQuery = (state) => {
  const componentBasedAdditions =
    state &&
    Array.isArray(state.layout) &&
    state.layout.map((item, index) => componentList[item.i].gqlFragment || "").join("");
  return gql`
        query QUERY_DASHBOARD_DETAILS { ${componentBasedAdditions || ""}
            monthly_sales: jobs(where: {_and: [
                { voided: {_eq: false}},
                {date_invoiced: {_gte: "${dayjs()
                  .startOf("month")
                  .startOf("day")
                  .toISOString()}"}}, {date_invoiced: {_lte: "${dayjs()
                  .endOf("month")
                  .endOf("day")
                  .toISOString()}"}}]}) {
      id
                ro_number
                date_invoiced
                job_totals
                rate_la1
                rate_la2
                rate_la3
                rate_la4
                rate_laa
                rate_lab
                rate_lad
                rate_lae
                rate_laf
                rate_lag
                rate_lam
                rate_lar
                rate_las
                rate_lau
                rate_ma2s
                rate_ma2t
                rate_ma3s
                rate_mabl
                rate_macs
                rate_mahw
                rate_mapa
                rate_mash
                rate_matd
                joblines(where: { removed: { _eq: false } }) {
                    id
                    mod_lbr_ty
                    mod_lb_hrs
                    act_price
                    part_qty
                    part_type
                }
                }
                production_jobs: jobs(where: { inproduction: { _eq: true } }) {
                    id
                    ro_number
                    ins_co_nm
                    job_totals
                    joblines(where: { removed: { _eq: false } }) {
                    id
                    mod_lbr_ty
                    mod_lb_hrs
                    act_price
                    part_qty
                    part_type
                }
                labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) {
                    aggregate {
                        sum {
                            mod_lb_hrs
                        }
                    }
                }
                larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" }, removed: { _eq: false } }) {
                    aggregate {
                        sum {
                            mod_lb_hrs
                        }
                    }
                }
                }
            }`;
};
