import { DeleteFilled } from "@ant-design/icons";
import { useApolloClient, useMutation, useQuery } from "@apollo/client/react";
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
import { Button, Card, Col, Form, Input, InputNumber, Row, Select, Space, Switch } from "antd";
import ResponsiveTable from "../responsive-table/responsive-table.component";
import queryString from "query-string";
import { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { logImEXEvent } from "../../firebase/firebase.utils";
import {
  CHECK_EMPLOYEE_NUMBER,
  DELETE_VACATION,
  INSERT_EMPLOYEES,
  QUERY_EMPLOYEE_BY_ID,
  QUERY_USERS_BY_EMAIL,
  UPDATE_EMPLOYEE
} from "../../graphql/employees.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CiecaSelect from "../../utils/Ciecaselect";
import { DateFormatter } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
import AlertComponent from "../alert/alert.component";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
import FormsFieldChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import ConfigListEmptyState from "../layout-form-row/config-list-empty-state.component.jsx";
import InlineValidatedFormRow from "../layout-form-row/inline-validated-form-row.component.jsx";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import {
  INLINE_TITLE_GROUP_STYLE,
  INLINE_TITLE_HANDLE_STYLE,
  INLINE_TITLE_INPUT_STYLE,
  INLINE_TITLE_LABEL_STYLE,
  INLINE_TITLE_ROW_STYLE,
  INLINE_TITLE_SEPARATOR_STYLE,
  INLINE_TITLE_SWITCH_GROUP_STYLE,
  INLINE_TITLE_TEXT_STYLE,
  InlineTitleListIcon
} from "../layout-form-row/inline-form-row-title.utils.js";
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component.jsx";

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

export function ShopEmployeesFormComponent({ bodyshop, form, onDirtyChange, isDirty }) {
  const submitActionRef = useRef("save");
  const { t } = useTranslation();
  const [internalIsDirty, setInternalIsDirty] = useState(false);
  const resolvedIsDirty = typeof isDirty === "boolean" ? isDirty : internalIsDirty;
  const employeeNumber = Form.useWatch("employee_number", form);
  const firstName = Form.useWatch("first_name", form);
  const lastName = Form.useWatch("last_name", form);
  const employeeOptionsColProps = {
    xs: 24,
    sm: 12,
    md: 12,
    lg: 8,
    xl: 8,
    xxl: 8
  };
  const history = useNavigate();
  const search = queryString.parse(useLocation().search);
  const [deleteVacation] = useMutation(DELETE_VACATION);
  const { error, data, refetch } = useQuery(QUERY_EMPLOYEE_BY_ID, {
    variables: { id: search.employeeId },
    skip: !search.employeeId || search.employeeId === "new",
    fetchPolicy: "network-only",
    nextFetchPolicy: "network-only"
  });
  const notification = useNotification();
  const isNewEmployee = search.employeeId === "new";
  const currentEmployeeData = data?.employees_by_pk?.id === search.employeeId ? data.employees_by_pk : null;
  const employeeTitleName = [firstName, lastName].filter(Boolean).join(" ").trim();
  const employeeCardTitle =
    [employeeNumber, employeeTitleName].filter(Boolean).join(" - ") ||
    (isNewEmployee ? t("employees.actions.new") : t("bodyshop.labels.employees"));

  const {
    treatments: { Enhanced_Payroll }
  } = useTreatmentsWithConfig({
    attributes: {},
    names: ["Enhanced_Payroll"],
    splitKey: bodyshop.imexshopid
  });

  const updateDirtyState = useCallback(
    (nextDirtyState) => {
      setInternalIsDirty(nextDirtyState);
      onDirtyChange?.(nextDirtyState);
    },
    [onDirtyChange]
  );

  const client = useApolloClient();
  const clearEmployeeFormMeta = useCallback(() => {
    const fieldMeta = form.getFieldsError().map(({ name }) => ({
      name,
      touched: false,
      validating: false,
      errors: [],
      warnings: []
    }));

    if (fieldMeta.length > 0) {
      form.setFields(fieldMeta);
    }

    updateDirtyState(false);
  }, [form, updateDirtyState]);

  const resetEmployeeFormToCurrentData = useCallback(() => {
    form.resetFields();

    if (currentEmployeeData) {
      form.setFieldsValue(currentEmployeeData);
    }

    window.requestAnimationFrame(() => {
      clearEmployeeFormMeta();
    });
  }, [clearEmployeeFormMeta, currentEmployeeData, form]);

  const syncEmployeeFormToSavedData = useCallback(
    (employeeData) => {
      if (employeeData) {
        form.setFieldsValue(employeeData);
      }

      window.requestAnimationFrame(() => {
        clearEmployeeFormMeta();
      });
    },
    [clearEmployeeFormMeta, form]
  );

  useEffect(() => {
    resetEmployeeFormToCurrentData();
  }, [resetEmployeeFormToCurrentData, search.employeeId]);

  const [updateEmployee] = useMutation(UPDATE_EMPLOYEE);
  const [insertEmployees] = useMutation(INSERT_EMPLOYEES);
  const saveAndResetSubmitAction = useCallback(() => {
    const submitAction = submitActionRef.current;
    submitActionRef.current = "save";
    return submitAction;
  }, []);
  const submitEmployeeForm = useCallback(
    (submitAction = "save") => {
      submitActionRef.current = submitAction;
      form.submit();
    },
    [form]
  );
  const navigateToEmployee = useCallback(
    (employeeId) => {
      history({
        search: queryString.stringify({
          ...search,
          employeeId
        })
      });
    },
    [history, search]
  );

  const handleFinish = async (values) => {
    const submitAction = saveAndResetSubmitAction();
    const normalizedValues = {
      ...values,
      user_email: values.user_email === "" ? null : values.user_email
    };

    if (search.employeeId && search.employeeId !== "new") {
      //Update a record.
      logImEXEvent("shop_employee_update");

      try {
        const result = await updateEmployee({
          variables: {
            id: search.employeeId,
            employee: normalizedValues
          }
        });

        syncEmployeeFormToSavedData(result?.data?.update_employees?.returning?.[0] ?? normalizedValues);
        void refetch();
        if (submitAction === "saveAndNew") {
          navigateToEmployee("new");
        }
        notification.success({
          title: t("employees.successes.save")
        });
      } catch (error) {
        notification.error({
          title: t("employees.errors.save", {
            message: JSON.stringify(error)
          })
        });
      }

      return;
    }

    //New record, insert it.
    logImEXEvent("shop_employee_insert");

    try {
      const result = await insertEmployees({
        variables: { employees: [{ ...normalizedValues, shopid: bodyshop.id }] },
        refetchQueries: ["QUERY_EMPLOYEES"]
      });
      const savedEmployee = result?.data?.insert_employees?.returning?.[0];

      if (submitAction === "saveAndNew") {
        if (isNewEmployee) {
          resetEmployeeFormToCurrentData();
        }
        navigateToEmployee("new");
      } else if (savedEmployee?.id) {
        syncEmployeeFormToSavedData(savedEmployee ?? normalizedValues);
        navigateToEmployee(savedEmployee.id);
      } else {
        syncEmployeeFormToSavedData(savedEmployee ?? normalizedValues);
      }

      notification.success({
        title: t("employees.successes.save")
      });
    } catch (error) {
      notification.error({
        title: t("employees.errors.save", {
          message: JSON.stringify(error)
        })
      });
    }
  };

  if (!search.employeeId) return null;
  if (error) return <AlertComponent title={error.message} type="error" />;

  const columns = [
    {
      title: t("employees.fields.vacation.start"),
      dataIndex: "start",
      key: "start",
      render: (text) => <DateFormatter>{text}</DateFormatter>
    },
    {
      title: t("employees.fields.vacation.end"),
      dataIndex: "end",
      key: "end",
      render: (text) => <DateFormatter>{text}</DateFormatter>
    },
    {
      title: t("employees.fields.vacation.length"),
      dataIndex: "length",
      key: "length",
      render: (text, record) => dayjs(record.end).diff(dayjs(record.start), "day", true).toFixed(1)
    },
    {
      title: t("general.labels.actions"),
      dataIndex: "actions",
      key: "actions",
      render: (text, record) => (
        <Button
          type="text"
          danger
          onClick={async () => {
            await deleteVacation({
              variables: { id: record.id },
              update(cache) {
                cache.modify({
                  id: cache.identify({
                    id: data.employees_by_pk.id,
                    __typename: "employees"
                  }),

                  fields: {
                    employee_vacations(ex, { readField }) {
                      return ex.filter((vacaref) => record.id !== readField("id", vacaref));
                    }
                  }
                });
              }
            });
          }}
          icon={<DeleteFilled />}
        />
      )
    }
  ];

  return (
    <Card
      title={employeeCardTitle}
      extra={
        <Space wrap>
          <Button onClick={() => submitEmployeeForm("saveAndNew")} disabled={!resolvedIsDirty} style={{ minWidth: 170 }}>
            {t("general.actions.saveandnew") || "Save and New"}
          </Button>
          <Button
            type="primary"
            onClick={() => submitEmployeeForm("save")}
            disabled={!resolvedIsDirty}
            style={{ minWidth: 170 }}
          >
            {t("employees.actions.save_employee")}
          </Button>
        </Space>
      }
    >
      <Form
        onFinish={handleFinish}
        onFinishFailed={saveAndResetSubmitAction}
        autoComplete={"off"}
        layout="vertical"
        form={form}
        onValuesChange={() => {
          updateDirtyState(form.isFieldsTouched());
        }}
      >
        <FormsFieldChanged form={form} onReset={resetEmployeeFormToCurrentData} onDirtyChange={updateDirtyState} />
        <LayoutFormRow
          title={
            <div
              style={{
                ...INLINE_TITLE_ROW_STYLE,
                justifyContent: "space-between"
              }}
            >
              <div
                style={{
                  ...INLINE_TITLE_TEXT_STYLE,
                  marginRight: "auto"
                }}
              >
                {t("bodyshop.labels.employee_options")}
              </div>
              <div
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 4,
                  flexWrap: "wrap",
                  marginLeft: "auto"
                }}
              >
                <div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
                <div
                  style={{
                    ...INLINE_TITLE_SWITCH_GROUP_STYLE
                  }}
                >
                  <div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.labels.active")}</div>
                  <Form.Item noStyle valuePropName="checked" name="active">
                    <Switch />
                  </Form.Item>
                </div>
                <div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
                <div
                  style={{
                    ...INLINE_TITLE_SWITCH_GROUP_STYLE
                  }}
                >
                  <div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.fields.flat_rate")}</div>
                  <Form.Item noStyle valuePropName="checked" name="flat_rate">
                    <Switch />
                  </Form.Item>
                </div>
              </div>
            </div>
          }
          wrapTitle
        >
          <Row gutter={[16, 16]} wrap>
            <Col {...employeeOptionsColProps}>
              <Form.Item
                name="first_name"
                label={t("employees.fields.first_name")}
                rules={[
                  {
                    required: true
                    //message: t("general.validation.required"),
                  }
                ]}
              >
                <Input />
              </Form.Item>
            </Col>
            <Col {...employeeOptionsColProps}>
              <Form.Item
                label={t("employees.fields.last_name")}
                name="last_name"
                rules={[
                  {
                    required: true
                    //message: t("general.validation.required"),
                  }
                ]}
              >
                <Input />
              </Form.Item>
            </Col>
            <Col {...employeeOptionsColProps}>
              <Form.Item
                name="employee_number"
                label={t("employees.fields.employee_number")}
                validateTrigger="onBlur"
                hasFeedback
                rules={[
                  {
                    required: true
                    //message: t("general.validation.required"),
                  },
                  () => ({
                    async validator(rule, value) {
                      if (value) {
                        const response = await client.query({
                          query: CHECK_EMPLOYEE_NUMBER,
                          variables: {
                            employeenumber: value
                          }
                        });

                        if (response.data.employees_aggregate.aggregate.count === 0) {
                          return Promise.resolve();
                        } else if (
                          response.data.employees_aggregate.nodes.length === 1 &&
                          response.data.employees_aggregate.nodes[0].id === form.getFieldValue("id")
                        ) {
                          return Promise.resolve();
                        }
                        return Promise.reject(t("employees.validation.unique_employee_number"));
                      } else {
                        return Promise.resolve();
                      }
                    }
                  })
                ]}
              >
                <Input />
              </Form.Item>
            </Col>
            <Col {...employeeOptionsColProps}>
              <Form.Item
                label={t("employees.fields.pin")}
                name="pin"
                rules={[
                  {
                    required: true
                    //message: t("general.validation.required"),
                  }
                ]}
              >
                <Input />
              </Form.Item>
            </Col>
            <Col {...employeeOptionsColProps}>
              <Form.Item
                name="hire_date"
                label={t("employees.fields.hire_date")}
                rules={[
                  {
                    required: true
                    //message: t("general.validation.required"),
                  }
                ]}
              >
                <DateTimePicker isDateOnly />
              </Form.Item>
            </Col>
            <Col {...employeeOptionsColProps}>
              <Form.Item label={t("employees.fields.termination_date")} name="termination_date">
                <DateTimePicker isDateOnly />
              </Form.Item>
            </Col>
            <Col {...employeeOptionsColProps}>
              <Form.Item
                label={t("employees.fields.user_email")}
                name="user_email"
                validateTrigger="onBlur"
                rules={[
                  ({ getFieldValue }) => ({
                    async validator(rule, value) {
                      const user_email = getFieldValue("user_email");

                      if (user_email && value) {
                        const response = await client.query({
                          query: QUERY_USERS_BY_EMAIL,
                          variables: {
                            email: user_email
                          }
                        });

                        if (response.data.users.length === 1) {
                          return Promise.resolve();
                        }
                        return Promise.reject(t("bodyshop.validation.useremailmustexist"));
                      } else {
                        return Promise.resolve();
                      }
                    }
                  })
                ]}
              >
                <FormItemEmail />
              </Form.Item>
            </Col>
            <Col {...employeeOptionsColProps}>
              <Form.Item label={t("employees.fields.external_id")} name="external_id">
                <Input />
              </Form.Item>
            </Col>
          </Row>
        </LayoutFormRow>
        <Form.List name={["rates"]}>
          {(fields, { add, remove, move }) => {
            return (
              <LayoutFormRow
                title={t("bodyshop.labels.employee_rates")}
                actions={[
                  <Button
                    key="add-rate"
                    type="primary"
                    block
                    onClick={() => {
                      add();
                    }}
                    id="add-employee-rate-button"
                  >
                    <span id="new-employee-rate">{t("employees.actions.addrate")}</span>
                  </Button>
                ]}
              >
                <div>
                  {fields.length === 0 ? (
                    <ConfigListEmptyState actionLabel={t("employees.actions.addrate")} />
                  ) : (
                    fields.map((field, index) => {
                      return (
                        <Form.Item noStyle key={field.key}>
                          <InlineValidatedFormRow
                            form={form}
                            errorNames={[["rates", field.name, "cost_center"]]}
                            noDivider
                            title={
                              <div style={INLINE_TITLE_ROW_STYLE}>
                                <InlineTitleListIcon style={INLINE_TITLE_HANDLE_STYLE} />
                                <div style={INLINE_TITLE_GROUP_STYLE}>
                                  <div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.fields.cost_center")}</div>
                                  <Form.Item
                                    noStyle
                                    name={[field.name, "cost_center"]}
                                    rules={[
                                      {
                                        required: true
                                      }
                                    ]}
                                  >
                                    <Select
                                      size="small"
                                      options={[
                                        { value: "timetickets.labels.shift", label: t("timetickets.labels.shift") },
                                        ...(bodyshop.cdk_dealerid ||
                                        bodyshop.pbs_serialnumber ||
                                        bodyshop.rr_dealerid ||
                                        Enhanced_Payroll.treatment === "on"
                                          ? CiecaSelect(false, true)
                                          : bodyshop.md_responsibility_centers.costs.map((c) => ({
                                              value: c.name,
                                              label: c.name
                                            })))
                                      ]}
                                      style={{ width: "100%" }}
                                      styles={{
                                        selector: INLINE_TITLE_INPUT_STYLE
                                      }}
                                    />
                                  </Form.Item>
                                </div>
                              </div>
                            }
                            wrapTitle
                            extra={
                              <Space align="center" size="small">
                                <Button
                                  type="text"
                                  danger
                                  icon={<DeleteFilled />}
                                  onClick={() => {
                                    remove(field.name);
                                  }}
                                />
                                <FormListMoveArrows
                                  move={move}
                                  index={index}
                                  total={fields.length}
                                  orientation="horizontal"
                                />
                              </Space>
                            }
                          >
                            <Form.Item
                              label={t("employees.fields.rate")}
                              name={[field.name, "rate"]}
                              rules={[
                                {
                                  required: true
                                }
                              ]}
                              style={{ marginBottom: 0 }}
                            >
                              <InputNumber min={0} precision={2} style={{ width: "100%" }} />
                            </Form.Item>
                          </InlineValidatedFormRow>
                        </Form.Item>
                      );
                    })
                  )}
                </div>
              </LayoutFormRow>
            );
          }}
        </Form.List>
      </Form>

      <LayoutFormRow
        title={t("bodyshop.labels.employee_vacation")}
        actions={[
          <ShopEmployeeAddVacation
            key="add-vacation"
            employee={data && data.employees_by_pk}
            buttonProps={{
              type: "primary",
              block: true
            }}
          />
        ]}
      >
        {(data?.employees_by_pk?.employee_vacations ?? []).length === 0 ? (
          <ConfigListEmptyState actionLabel={t("employees.actions.addvacation")} />
        ) : (
          <div>
            <ResponsiveTable
              columns={columns}
              mobileColumnKeys={["start", "length", "actions"]}
              rowKey={"id"}
              dataSource={data?.employees_by_pk?.employee_vacations ?? []}
              pagination={false}
            />
          </div>
        )}
      </LayoutFormRow>
    </Card>
  );
}

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