import Icon, { SyncOutlined } from "@ant-design/icons";
import { gql, useMutation, useQuery } from "@apollo/client";
import { Button, Dropdown, Menu, notification, PageHeader, Space } from "antd";
import i18next from "i18next";
import _ from "lodash";
import moment from "moment";
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 "./dashboard-grid.styles.scss";
import { GenerateDashboardData } from "./dashboard-grid.utils";

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 { 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 addComponentOverlay = (
    <Menu onClick={handleAddComponent}>
      {Object.keys(componentList).map((key) => (
        <Menu.Item
          key={key}
          value={key}
          disabled={existingLayoutKeys.includes(key)}
        >
          {componentList[key].label}
        </Menu.Item>
      ))}
    </Menu>
  );

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

  return (
    <div>
      <PageHeader
        extra={
          <Space>
            <Button onClick={() => refetch()}>
              <SyncOutlined />
            </Button>
            <Dropdown overlay={addComponentOverlay} 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" 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,
  },
  MonthlyEmployeeEfficency: {
    label: i18next.t("dashboard.titles.monthlyemployeeefficiency"),
    component: DashboardMonthlyEmployeeEfficiency,
    gqlFragment: DashboardMonthlyEmployeeEfficiencyGql,
    minW: 2,
    minH: 2,
    w: 2,
    h: 2,
  },
};

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: "${moment()
        .startOf("month").startOf('day').toISOString()}"}}, {date_invoiced: {_lte: "${moment()
    .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
            }
          }
        }
      }
    }
  `;
};
