import { DownCircleFilled } from "@ant-design/icons";
import { useApolloClient, useMutation, useQuery } from "@apollo/client/react";
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
import { Button, Card, Dropdown, Form, Input, Modal, Popover, Select, Space } from "antd";
import axios from "axios";
import parsePhoneNumber from "libphonenumber-js";
import { useCallback, useMemo, useRef, useState } from "react";
import { HasRbacAccess } from "../../components/rbac-wrapper/rbac-wrapper.component";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { useSocket } from "../../contexts/SocketIO/useSocket.js";
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
import { CANCEL_APPOINTMENTS_BY_JOB_ID, INSERT_MANUAL_APPT } from "../../graphql/appointments.queries";
import { GET_CURRENT_QUESTIONSET_ID, INSERT_CSI } from "../../graphql/csi.queries";
import { DELETE_JOB, GET_JOB_WATCHERS, UPDATE_JOB, VOID_JOB } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setEmailOptions } from "../../redux/email/email.actions";
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectAuthLevel, selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import { TemplateList } from "../../utils/TemplateConstants";
import dayjs from "../../utils/day";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
import LockerWrapperComponent from "../lock-wrapper/lock-wrapper.component";
import ShareToTeamsButton from "../share-to-teams/share-to-teams.component.jsx";
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
import JobsDetailHeaderActionsToggleProduction from "./jobs-detail-header-actions.toggle-production";

const EMPTY_ARRAY = Object.freeze([]);

const mapStateToProps = createStructuredSelector({
  bodyshop: selectBodyshop,
  jobRO: selectJobReadOnly,
  currentUser: selectCurrentUser,
  authLevel: selectAuthLevel
});

const mapDispatchToProps = (dispatch) => ({
  setScheduleContext: (context) => dispatch(setModalContext({ context: context, modal: "schedule" })),
  setBillEnterContext: (context) =>
    dispatch(
      setModalContext({
        context: context,
        modal: "billEnter"
      })
    ),
  setPaymentContext: (context) => dispatch(setModalContext({ context: context, modal: "payment" })),
  setJobCostingContext: (context) =>
    dispatch(
      setModalContext({
        context: context,
        modal: "jobCosting"
      })
    ),
  setTimeTicketContext: (context) =>
    dispatch(
      setModalContext({
        context: context,
        modal: "timeTicket"
      })
    ),
  setCardPaymentContext: (context) =>
    dispatch(
      setModalContext({
        context: context,
        modal: "cardPayment"
      })
    ),
  insertAuditTrail: ({ jobid, operation, type }) =>
    dispatch(
      insertAuditTrail({
        jobid,
        operation,
        type
      })
    ),
  setTimeTicketTaskContext: (context) =>
    dispatch(
      setModalContext({
        context: context,
        modal: "timeTicketTask"
      })
    ),
  setTaskUpsertContext: (context) =>
    dispatch(
      setModalContext({
        context: context,
        modal: "taskUpsert"
      })
    ),
  setEmailOptions: (e) => dispatch(setEmailOptions(e)),
  openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
  setMessage: (text) => dispatch(setMessage(text))
});

export function JobsDetailHeaderActions({
  job,
  bodyshop,
  currentUser,
  refetch,
  setScheduleContext,
  setBillEnterContext,
  setPaymentContext,
  setJobCostingContext,
  jobRO,
  setTimeTicketContext,
  setCardPaymentContext,
  insertAuditTrail,
  setEmailOptions,
  openChatByPhone,
  setMessage,
  setTimeTicketTaskContext,
  setTaskUpsertContext,
  authLevel
}) {
  const { t } = useTranslation();
  const client = useApolloClient();
  const history = useNavigate();
  const [form] = Form.useForm();
  const [loading, setLoading] = useState(false);
  const [dropdownOpen, setDropdownOpen] = useState(false);
  const [visibility, setVisibility] = useState(false);
  const jobId = job?.id;
  const watcherVars = useMemo(() => ({ jobid: jobId }), [jobId]);

  const [isCancelScheduleModalVisible, setIsCancelScheduleModalVisible] = useState(false);
  const [insertAppointment] = useMutation(INSERT_MANUAL_APPT);
  const [deleteJob] = useMutation(DELETE_JOB);
  const [insertCsi] = useMutation(INSERT_CSI);
  const [updateJob] = useMutation(UPDATE_JOB);
  const [voidJob] = useMutation(VOID_JOB);
  const [cancelAllAppointments] = useMutation(CANCEL_APPOINTMENTS_BY_JOB_ID);
  const { socket } = useSocket();
  const notification = useNotification();

  const isDevEnv = import.meta.env.DEV;
  const isProdEnv = import.meta.env.PROD;
  const userEmail = currentUser?.email || "";

  const devEmails = ["imex.dev", "rome.dev"];
  const prodEmails = ["imex.prod", "rome.prod", "imex.test", "rome.test"];

  const canVoidJob = useMemo(() => HasRbacAccess({ authLevel, bodyshop, action: "jobs:void" }), [authLevel, bodyshop]);

  const hasValidEmail = (emails) => emails.some((email) => userEmail.endsWith(email));
  const canSubmitForTesting = (isDevEnv && hasValidEmail(devEmails)) || (isProdEnv && hasValidEmail(prodEmails));

  const { data: jobWatchersData } = useQuery(GET_JOB_WATCHERS, {
    variables: watcherVars,
    skip: !jobId,
    fetchPolicy: "cache-first",
  });

  const jobWatchersCount = jobWatchersData?.job_watchers?.length ?? job?.job_watchers?.length ?? 0;

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

  const productionStatuses = bodyshop?.md_ro_statuses?.production_statuses ?? EMPTY_ARRAY;
  const preProductionStatuses = bodyshop?.md_ro_statuses?.pre_production_statuses ?? EMPTY_ARRAY;
  const postProductionStatuses = bodyshop?.md_ro_statuses?.post_production_statuses ?? EMPTY_ARRAY;
  const jobStatus = job?.status;

  const jobInProduction = productionStatuses.includes(jobStatus);
  const jobInPreProduction = preProductionStatuses.includes(jobStatus);
  const jobInPostProduction = postProductionStatuses.includes(jobStatus);

  const makeConfirmId = () =>
    globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(16).slice(2)}`;

  const [modal, modalContextHolder] = Modal.useModal();

  const confirmInstancesRef = useRef(new Map());

  const closeConfirmById = (id) => {
    const inst = confirmInstancesRef.current.get(id);
    if (inst) inst.destroy(); // hard close
    confirmInstancesRef.current.delete(id);
  };

  const openConfirmFromMenu = ({
    variant = "confirm", // "confirm" | "info" | "warning"
    title,
    content,
    okText,
    cancelText,
    showCancel = true,
    onOk,
    onCancel
  }) => {
    // close the dropdown immediately; confirm dialog is separate
    setDropdownOpen(false);

    const id = makeConfirmId();

    const openFn = variant === "info" ? modal.info : variant === "warning" ? modal.warning : modal.confirm;

    const inst = openFn({
      title,
      content,
      okText,
      cancelText,
      centered: true,
      mask: { closable: false },
      onCancel: () => {
        closeConfirmById(id);
        onCancel?.();
      },
      onOk: async () => {
        try {
          await onOk?.();
        } finally {
          closeConfirmById(id);
        }
      },
      ...(showCancel ? {} : { okCancel: false })
    });

    confirmInstancesRef.current.set(id, inst);
    return id;
  };

  const handleDropdownOpenChange = useCallback((nextOpen) => {
    setDropdownOpen(nextOpen);
  }, []);

  const showCancelScheduleModal = () => {
    setIsCancelScheduleModalVisible(true);
  };

  const handleCancelScheduleModalCancel = () => {
    setIsCancelScheduleModalVisible(false);
  };

  const handleDuplicate = () =>
    DuplicateJob({
      apolloClient: client,
      jobId: job.id,
      config: { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported, timezone: bodyshop.timezone },
      completionCallback: (newJobId) => {
        history(`/manage/jobs/${newJobId}`);
        notification.success({
          title: t("jobs.successes.duplicated")
        });
      },
      keepJobLines: true,
      currentUser
    });

  const handleDuplicateConfirm = () =>
    DuplicateJob({
      apolloClient: client,
      jobId: job.id,
      config: { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported, timezone: bodyshop.timezone },
      completionCallback: (newJobId) => {
        history(`/manage/jobs/${newJobId}`);
        notification.success({
          title: t("jobs.successes.duplicated")
        });
      },
      keepJobLines: false,
      currentUser
    });

  const handleFinish = async (values) => {
    logImEXEvent("schedule_manual_event");

    setLoading(true);
    try {
      insertAppointment({
        variables: {
          apt: { ...values, isintake: false, jobid: job.id, bodyshopid: bodyshop.id }
        },
        refetchQueries: ["QUERY_ALL_ACTIVE_APPOINTMENTS"]
      });
      notification.success({
        title: t("appointments.successes.created")
      });
    } catch (error) {
      notification.error({
        title: t("appointments.errors.saving", { error: error.message })
      });
    } finally {
      setLoading(false);
      setVisibility(false);
    }
  };

  const handleDeleteJob = async () => {
    //delete the job.
    const result = await deleteJob({ variables: { id: job.id } });

    if (!result.errors) {
      notification.success({
        title: t("jobs.successes.delete")
      });
      //go back to jobs list.
      history(`/manage/`);
    } else {
      notification.error({
        title: t("jobs.errors.deleted", {
          error: JSON.stringify(result.errors)
        })
      });
    }
  };

  const handleCreateCsi = async (e) => {
    logImEXEvent("job_create_csi");

    //Is there already a CSI?
    if (!job.csiinvites || job.csiinvites.length === 0) {
      const questionSetResult = await client.query({
        query: GET_CURRENT_QUESTIONSET_ID
      });

      if (questionSetResult.data.csiquestions.length > 0) {
        const result = await insertCsi({
          variables: {
            csiInput: {
              jobid: job.id,
              bodyshopid: bodyshop.id,
              questionset: questionSetResult.data.csiquestions[0].id,
              relateddata: {
                job: {
                  id: job.id,
                  ownr_fn: job.ownr_fn,
                  ro_number: job.ro_number,
                  v_model_yr: job.v_model_yr,
                  v_make_desc: job.v_make_desc,
                  v_model_desc: job.v_model_desc
                },
                bodyshop: {
                  city: bodyshop.city,
                  email: bodyshop.email,
                  state: bodyshop.state,
                  country: bodyshop.country,
                  address1: bodyshop.address1,
                  address2: bodyshop.address2,
                  shopname: bodyshop.shopname,
                  zip_post: bodyshop.zip_post,
                  logo_img_path: bodyshop.logo_img_path
                }
              }
            }
          },
          refetchQueries: ["GET_JOB_BY_PK"],
          awaitRefetchQueries: true
        });

        if (!result.errors) {
          notification.success({ title: t("csi.successes.created") });
        } else {
          notification.error({
            title: t("csi.errors.creating", {
              message: JSON.stringify(result.errors)
            })
          });
          insertAuditTrail({
            jobid: job.id,
            operation: AuditTrailMapping.jobvoid(),
            type: "jobvoid"
          });
          return;
        }
        if (e.key === "email")
          setEmailOptions({
            jobid: job.id,
            messageOptions: {
              to: [job.ownr_ea],
              replyTo: bodyshop.email
            },
            template: {
              name: TemplateList("job_special").csi_invitation_action.key,
              variables: {
                id: result.data.insert_csi.returning[0].id
              }
            }
          });

        if (e.key === "text") {
          const p = parsePhoneNumber(job.ownr_ph1, "CA");
          if (p && p.isValid()) {
            openChatByPhone({
              phone_num: p.formatInternational(),
              jobid: job.id,
              socket
            });
            setMessage(
              `${window.location.protocol}//${window.location.host}/csi/${result.data.insert_csi.returning[0].id}`
            );
          } else {
            notification.error({
              title: t("messaging.error.invalidphone")
            });
          }
        }
        if (e.key === "generate") {
          //copy it to clipboard.
          navigator.clipboard.writeText(
            `${window.location.protocol}//${window.location.host}/csi/${result.data.insert_csi.returning[0].id}`
          );
        }
      } else {
        notification.error({
          title: t("csi.errors.notconfigured")
        });
      }
    } else {
      if (e.key === "email")
        setEmailOptions({
          jobid: job.id,
          messageOptions: {
            to: [job.ownr_ea],
            replyTo: bodyshop.email
          },
          template: {
            name: TemplateList("job_special").csi_invitation_action.key,
            variables: {
              id: job.csiinvites[0].id
            }
          }
        });

      if (e.key === "text") {
        const p = parsePhoneNumber(job.ownr_ph1, "CA");
        if (p && p.isValid()) {
          openChatByPhone({
            phone_num: p.formatInternational(),
            jobid: job.id,
            socket
          });
          setMessage(`${window.location.protocol}//${window.location.host}/csi/${job.csiinvites[0].id}`);
        } else {
          notification.error({
            title: t("messaging.error.invalidphone")
          });
        }
      }

      if (e.key === "generate") {
        //copy it to clipboard.
        navigator.clipboard.writeText(
          `${window.location.protocol}//${window.location.host}/csi/${job.csiinvites[0].id}`
        );
      }
    }
  };

  const handleVoidJob = async () => {
    if (!canVoidJob) {
      notification.error({ title: t("general.messages.rbacunauth") });
      return;
    }

    //delete the job.
    const result = await voidJob({
      variables: {
        jobId: job.id,
        job: {
          status: bodyshop.md_ro_statuses.default_void,
          voided: true,
          scheduled_in: null,
          scheduled_completion: null,
          inproduction: false,
          date_void: new Date()
        },
        note: [
          {
            jobid: job.id,
            created_by: currentUser.email,
            audit: true,
            text: t("jobs.labels.voidnote")
          }
        ]
      }
    });

    if (!result.errors) {
      notification.success({
        title: t("jobs.successes.voided")
      });
      insertAuditTrail({
        jobid: job.id,
        operation: AuditTrailMapping.jobvoid(),
        type: "jobvoid"
      });
      //go back to jobs list.
      history(`/manage/`);
    } else {
      notification.error({
        title: t("jobs.errors.voiding", {
          error: JSON.stringify(result.errors)
        })
      });
    }
  };

  const handleExportCustData = async () => {
    logImEXEvent("job_export_cust_data");
    let PartnerResponse;
    if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
      PartnerResponse = await axios.post(`/qbo/receivables`, {
        jobIds: [job.id],
        custDataOnly: true
      });
    } else {
      //Default is QBD

      let QbXmlResponse;
      try {
        QbXmlResponse = await axios.post(
          "/accounting/qbxml/receivables",
          { jobIds: [job.id], custDataOnly: true },
          {
            headers: {
              Authorization: `Bearer ${await auth.currentUser.getIdToken()}`
            }
          }
        );
        console.log("handle -> XML", QbXmlResponse);
      } catch (error) {
        console.log("Error getting QBXML from Server.", error);
        notification.error({
          title: t("jobs.errors.exporting", {
            error: "Unable to retrieve QBXML. " + JSON.stringify(error.message)
          })
        });

        return;
      }

      //let PartnerResponse;
      try {
        PartnerResponse = await axios.post("http://localhost:1337/qb/", QbXmlResponse.data, {
          headers: {
            Authorization: `Bearer ${await auth.currentUser.getIdToken()}`
          }
        });
      } catch (error) {
        console.log("Error connecting to quickbooks or partner.", error);
        notification.error({
          title: t("jobs.errors.exporting-partner")
        });

        return;
      }
    }
    //Check to see if any of them failed. If they didn't  execute the update.
    const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
    if (failedTransactions.length > 0) {
      //Uh oh. At least one was no good.
      failedTransactions.forEach((ft) => {
        //insert failed export log
        notification.error({
          // key: "failedexports",
          title: t("jobs.errors.exporting", {
            error: ft.errorMessage || ""
          })
        });
      });

      //Handle Failures.
    } else {
      //Insert success export log.

      notification.success({
        key: "jobsuccessexport",
        title: t("jobs.successes.exported")
      });
    }
  };

  const handleAlertToggle = () => {
    logImEXEvent("production_toggle_alert");
    //e.stopPropagation();
    updateJob({
      variables: {
        jobId: job.id,
        job: {
          production_vars: {
            ...job.production_vars,
            alert: !!job.production_vars && !!job.production_vars.alert ? !job.production_vars.alert : true
          }
        }
      }
    });
    insertAuditTrail({
      jobid: job.id,
      operation: AuditTrailMapping.alertToggle(
        !!job.production_vars && !!job.production_vars.alert ? !job.production_vars.alert : true
      ),
      type: "alertToggle"
    });
  };

  const handleSuspend = () => {
    logImEXEvent("production_toggle_alert");
    //e.stopPropagation();
    updateJob({
      variables: {
        jobId: job.id,
        job: {
          suspended: !job.suspended
        }
      }
    });
    insertAuditTrail({
      jobid: job.id,
      operation: AuditTrailMapping.jobsuspend(job.suspended ? !job.suspended : true),
      type: "jobsuspend"
    });
  };

  const handleLostSaleFinish = async ({ lost_sale_reason }) => {
    const jobUpdate = await cancelAllAppointments({
      variables: {
        jobid: job.id,
        job: {
          date_scheduled: null,
          scheduled_in: null,
          scheduled_completion: null,
          lost_sale_reason,
          date_lost_sale: new Date(),
          status: bodyshop.md_ro_statuses.default_imported
        }
      }
    });
    if (!jobUpdate.errors) {
      notification.success({
        title: t("appointments.successes.canceled")
      });
      insertAuditTrail({
        jobid: job.id,
        operation: AuditTrailMapping.appointmentcancel(lost_sale_reason),
        type: "appointmentcancel"
      });
    }
  };

  const popOverContent = (
    <Card>
      <div>
        <Form form={form} layout="vertical" onFinish={handleFinish}>
          <Form.Item
            label={t("appointments.fields.title")}
            name="title"
            rules={[
              {
                required: true
                //message: t("general.validation.required"),
              }
            ]}
          >
            <Input />
          </Form.Item>
          <Form.Item label={t("appointments.fields.note")} name="note">
            <Input />
          </Form.Item>
          <Form.Item
            label={t("appointments.fields.start")}
            name="start"
            rules={[
              {
                required: true
                //message: t("general.validation.required"),
              }
            ]}
          >
            <FormDateTimePickerComponent
              onBlur={() => {
                const start = form.getFieldValue("start");
                form.setFieldsValue({ end: start?.add(30, "minutes") });
              }}
            />
          </Form.Item>
          <Form.Item
            label={t("appointments.fields.end")}
            name="end"
            rules={[
              {
                required: true
                //message: t("general.validation.required"),
              },
              () => ({
                async validator(rule, value) {
                  if (value) {
                    const { start } = form.getFieldsValue();
                    if (dayjs(start).isAfter(dayjs(value))) {
                      return Promise.reject(t("employees.labels.endmustbeafterstart"));
                    } else {
                      return Promise.resolve();
                    }
                  } else {
                    return Promise.resolve();
                  }
                }
              })
            ]}
          >
            <FormDateTimePickerComponent />
          </Form.Item>
          <Form.Item label={t("appointments.fields.color")} name="color">
            <Select
              options={bodyshop.appt_colors.map((col) => ({
                value: col.color.hex,
                label: col.label
              }))}
            />
          </Form.Item>

          <Space wrap>
            <Button type="primary" htmlType="submit" loading={loading}>
              {t("general.actions.save")}
            </Button>
            <Button onClick={() => setVisibility(false)}>{t("general.actions.cancel")}</Button>
          </Space>
        </Form>
      </div>
    </Card>
  );

  const menuItems = [
    {
      key: "schedule",
      id: "job-actions-schedule",
      disabled: !jobInPreProduction || !job.converted || jobRO,
      label: t("jobs.actions.schedule"),
      onClick: () => {
        logImEXEvent("job_header_schedule");
        setScheduleContext({
          actions: { refetch: refetch },
          context: {
            jobId: job.id,
            job: job,
            alt_transport: job.alt_transport,
            scheduled_in: job.scheduled_in,
            scheduled_completion: job.scheduled_completion
          }
        });
      }
    },
    {
      key: "cancelallappointments",
      id: "job-actions-cancelallappointments",
      onClick: () => {
        if (job.status !== bodyshop.md_ro_statuses.default_scheduled) {
          return;
        }
        showCancelScheduleModal();
      },
      disabled: job.status !== bodyshop.md_ro_statuses.default_scheduled,
      label: t("menus.jobsactions.cancelallappointments")
    },
    {
      key: "intake",
      id: "job-actions-intake",
      disabled: !!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO,
      label:
        !!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO ? (
          <LockerWrapperComponent featureName="checklist">{t("jobs.actions.intake")}</LockerWrapperComponent>
        ) : (
          <Link to={`/manage/jobs/${job.id}/intake`}>
            <LockerWrapperComponent featureName="checklist">{t("jobs.actions.intake")}</LockerWrapperComponent>
          </Link>
        )
    },
    {
      key: "deliver",
      id: "job-actions-deliver",
      disabled: !jobInProduction || jobRO,
      label: !jobInProduction ? (
        <LockerWrapperComponent disabled featureName="checklist">
          {t("jobs.actions.deliver")}
        </LockerWrapperComponent>
      ) : (
        <Link to={`/manage/jobs/${job.id}/deliver`}>
          <LockerWrapperComponent disabled featureName="checklist">
            {t("jobs.actions.deliver")}
          </LockerWrapperComponent>
        </Link>
      )
    },
    {
      key: "checklist",
      id: "job-actions-checklist",
      disabled: !job.converted,
      label: (
        <Link to={`/manage/jobs/${job.id}/checklist`}>
          <LockerWrapperComponent featureName="checklist">{t("jobs.actions.viewchecklist")}</LockerWrapperComponent>
        </Link>
      )
    },
    {
      key: "toggleproduction",
      id: "job-actions-toggleproduction",
      disabled: !job.converted || jobRO,
      label: (
        <JobsDetailHeaderActionsToggleProduction
          job={job}
          refetch={refetch}
          closeParentMenu={() => setDropdownOpen(false)}
        />
      )
    },

    {
      key: "entertimetickets",
      id: "job-actions-entertimetickets",
      disabled: !job.converted || (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced),
      label: (
        <LockerWrapperComponent featureName="timetickets">{t("timetickets.actions.enter")}</LockerWrapperComponent>
      ),
      onClick: () => {
        logImEXEvent("job_header_enter_time_ticekts");

        HasFeatureAccess({ featureName: "timetickets", bodyshop }) &&
          setTimeTicketContext({
            actions: {},
            context: {
              jobId: job.id,
              created_by: currentUser.displayName
                ? currentUser.email.concat(" | ", currentUser.displayName)
                : currentUser.email
            }
          });
      }
    }
  ];

  if (bodyshop.md_tasks_presets.enable_tasks) {
    menuItems.push({
      key: "claimtimetickettasks",
      id: "job-actions-claimtimetickettasks",
      disabled: !job.converted || (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced),
      onClick: () => {
        setTimeTicketTaskContext({
          actions: {},
          context: { jobid: job.id }
        });
      },
      label: t("timetickets.actions.claimtasks")
    });
  }

  menuItems.push({
    key: "enterpayments",
    id: "job-actions-enterpayments",
    disabled: !job.converted,
    label: t("menus.header.enterpayment"),
    onClick: () => {
      logImEXEvent("job_header_enter_payment");

      setPaymentContext({
        actions: {},
        context: { jobid: job.id }
      });
    }
  });

  if (ImEXPay.treatment === "on") {
    menuItems.push({
      key: "entercardpayments",
      id: "job-actions-entercardpayments",
      disabled: !job.converted,
      label: t("menus.header.entercardpayment"),
      onClick: () => {
        logImEXEvent("job_header_enter_card_payment");

        setCardPaymentContext({
          actions: { refetch },
          context: { jobid: job.id }
        });
      }
    });
  }

  menuItems.push({
    key: "cccontract",
    id: "job-actions-cccontract",
    disabled: jobRO || !job.converted,
    label: (
      <Link state={{ jobId: job.id }} to="/manage/courtesycars/contracts/new">
        <LockerWrapperComponent featureName="courtesycars">
          {t("menus.jobsactions.newcccontract")}
        </LockerWrapperComponent>
      </Link>
    )
  });

  menuItems.push({
    key: "createtask",
    id: "job-actions-createtask",
    label: t("menus.header.create_task"),
    onClick: () =>
      setTaskUpsertContext({
        actions: {},
        context: { jobid: job.id }
      })
  });

  menuItems.push(
    job.inproduction
      ? {
          key: "removefromproduction",
          id: "job-actions-removefromproduction",
          disabled: !job.converted,
          label: t("jobs.actions.removefromproduction"),
          onClick: () => AddToProduction(client, job.id, refetch, true, notification)
        }
      : {
          key: "addtoproduction",
          id: "job-actions-addtoproduction",
          disabled: !job.converted,
          label: t("jobs.actions.addtoproduction"),
          onClick: () => AddToProduction(client, job.id, refetch, false, notification)
        }
  );

  menuItems.push(
    {
      key: "togglesuspend",
      id: "job-actions-togglesuspend",
      onClick: handleSuspend,
      label: job.suspended ? t("production.actions.unsuspend") : t("production.actions.suspend")
    },
    {
      key: "toggleAlert",
      onClick: handleAlertToggle,
      id: "job-actions-togglealert",
      label:
        job.production_vars && job.production_vars.alert
          ? t("production.labels.alertoff")
          : t("production.labels.alerton")
    },
    {
      key: "dupe",
      label: t("menus.jobsactions.duplicate"),
      children: [
        {
          key: "duplicate",
          id: "job-actions-duplicate",
          label: t("menus.jobsactions.duplicate"),
          onClick: () =>
            openConfirmFromMenu({
              title: t("jobs.labels.duplicateconfirm"),
              okText: t("general.labels.yes"),
              cancelText: t("general.labels.no"),
              onOk: handleDuplicate
            })
        },
        {
          key: "duplicatenolines",
          id: "job-actions-duplicatenolines",
          label: t("menus.jobsactions.duplicatenolines"),
          onClick: () =>
            openConfirmFromMenu({
              title: t("jobs.labels.duplicateconfirm"),
              okText: t("general.labels.yes"),
              cancelText: t("general.labels.no"),
              onOk: handleDuplicateConfirm
            })
        }
      ]
    },

    {
      key: "postbills",
      id: "job-actions-postbills",
      disabled: !job.converted,
      label: <LockerWrapperComponent featureName="bills">{t("jobs.actions.postbills")}</LockerWrapperComponent>,
      onClick: () => {
        logImEXEvent("job_header_enter_bills");
        HasFeatureAccess({ featureName: "bills", bodyshop }) &&
          setBillEnterContext({
            actions: { refetch: refetch },
            context: {
              job: job
            }
          });
      }
    },

    {
      key: "addtopartsqueue",
      id: "job-actions-addtopartsqueue",
      disabled: !job.converted || !jobInProduction || jobRO,
      label: t("jobs.actions.addtopartsqueue"),
      onClick: async () => {
        const result = await updateJob({
          variables: {
            jobId: job.id,
            job: { queued_for_parts: true }
          }
        });

        if (!result.errors) {
          notification.success({
            title: t("jobs.successes.partsqueue")
          });
        } else {
          notification.error({
            title: t("jobs.errors.saving", {
              error: JSON.stringify(result.errors)
            })
          });
        }
      }
    },
    {
      key: "closejob",
      id: "job-actions-closejob",
      disabled: !jobInPostProduction,
      label: !jobInPostProduction ? (
        t("menus.jobsactions.closejob")
      ) : (
        <Link
          to={{
            pathname: `/manage/jobs/${job.id}/close`
          }}
        >
          {t("menus.jobsactions.closejob")}
        </Link>
      )
    },
    {
      key: "admin",
      id: "job-actions-admin",
      label: (
        <Link
          to={{
            pathname: `/manage/jobs/${job.id}/admin`
          }}
        >
          {t("menus.jobsactions.admin")}
        </Link>
      )
    }
  );

  if (bodyshop?.md_functionality_toggles?.teams) {
    menuItems.push({
      key: "sharetoteams",
      id: "job-actions-sharetoteams",
      label: <ShareToTeamsButton noIcon={true} urlOverride={`${window.location.origin}${window.location.pathname}`} />
    });
  }

  menuItems.push({
    key: "exportcustdata",
    id: "job-actions-exportcustdata",
    disabled: !(job.converted && HasFeatureAccess({ bodyshop, featureName: "export" })),
    label: <LockerWrapperComponent featureName="export">{t("jobs.actions.exportcustdata")}</LockerWrapperComponent>,
    onClick: handleExportCustData
  });

  const children = [
    {
      key: "email",
      id: "job-actions-email",
      disabled: !(job.ownr_ea && HasFeatureAccess({ bodyshop, featureName: "csi" })),
      label: <LockerWrapperComponent featureName="checklist">{t("general.labels.email")}</LockerWrapperComponent>,
      onClick: handleCreateCsi
    },
    {
      key: "text",
      id: "job-actions-text",
      disabled: !(job.ownr_ph1 && HasFeatureAccess({ bodyshop, featureName: "csi" })),
      label: <LockerWrapperComponent featureName="checklist">{t("general.labels.text")}</LockerWrapperComponent>,
      onClick: handleCreateCsi
    },
    {
      key: "generate",
      id: "job-actions-generate",
      disabled: job.csiinvites?.length > 0 || !HasFeatureAccess({ bodyshop, featureName: "csi" }),
      label: <LockerWrapperComponent featureName="checklist">{t("jobs.actions.generatecsi")}</LockerWrapperComponent>,
      onClick: handleCreateCsi
    }
  ];

  if (job?.csiinvites?.length) {
    children.push(
      {
        type: "divider"
      },
      ...job.csiinvites.map((item, idx) => {
        return item.completedon
          ? {
              key: idx,
              label: (
                <Link to={`/manage/shop/csi?responseid=${item.id}`}>
                  <DateTimeFormatter>{item.completedon}</DateTimeFormatter>
                </Link>
              )
            }
          : {
              key: idx,
              onClick: () => {
                navigator.clipboard.writeText(`${window.location.protocol}//${window.location.host}/csi/${item.id}`);
              },
              label: t("general.actions.copylink")
            };
      })
    );
  }
  menuItems.push({
    key: "sendcsi",
    id: "job-actions-sendcsi",
    label: <LockerWrapperComponent featureName="checklist">{t("jobs.actions.sendcsi")}</LockerWrapperComponent>,
    disabled: !job.converted,
    children
  });

  menuItems.push({
    key: "jobcosting",
    id: "job-actions-jobcosting",
    disabled: !job.converted,
    label: t("jobs.labels.jobcosting"),
    onClick: () => {
      logImEXEvent("job_header_job_costing");

      setJobCostingContext({
        actions: { refetch: refetch },
        context: {
          jobId: job.id
        }
      });
    }
  });

  if (job && !job.converted) {
    menuItems.push({
      key: "deletejob",
      id: "job-actions-deletejob",
      label: t("menus.jobsactions.deletejob"),
      onClick: () => {
        if (jobWatchersCount === 0) {
          openConfirmFromMenu({
            title: t("jobs.labels.deleteconfirm"),
            okText: t("general.labels.yes"),
            cancelText: t("general.labels.no"),
            onOk: handleDeleteJob
          });
        } else {
          // informational "OK only"
          openConfirmFromMenu({
            variant: "info",
            title: t("jobs.labels.deletewatchers"),
            okText: t("general.actions.ok"),
            showCancel: false
          });
        }
      }
    });
  }

  menuItems.push({
    key: "manualevent",
    id: "job-actions-manualevent",
    onClick: () => {
      setVisibility(true);
    },
    label: t("appointments.labels.manualevent")
  });

  if (!jobRO && job.converted && canVoidJob) {
    menuItems.push({
      key: "voidjob",
      id: "job-actions-voidjob",
      label: t("menus.jobsactions.void"),
      onClick: () =>
        openConfirmFromMenu({
          title: t("jobs.labels.voidjob"),
          okText: t("general.labels.yes"),
          cancelText: t("general.labels.no"),
          onOk: handleVoidJob
        })
    });
  }

  if (canSubmitForTesting) {
    menuItems.push({
      key: "submitfortesting",
      id: "job-actions-submitfortesting",
      label: t("menus.jobsactions.submit-for-testing"),
      onClick: async () => {
        try {
          await axios.post("/job/totals-recorder", { id: job.id });
          notification.success({
            title: t("general.messages.submit-for-testing")
          });
        } catch (err) {
          console.error(`Error submitting job for testing: ${err?.message}`);
          notification.error({
            title: t("general.errors.submit-for-testing-error")
          });
        }
      }
    });
  }

  const menu = {
    items: menuItems,
    key: "popovermenu"
  };

  return (
    <>
      {modalContextHolder}
      <Modal
        title={t("menus.jobsactions.cancelallappointments")}
        open={isCancelScheduleModalVisible}
        onCancel={handleCancelScheduleModalCancel}
        footer={[
          <Button form="cancelScheduleForm" key="back" onClick={handleCancelScheduleModalCancel}>
            {t("general.actions.cancel")}
          </Button>,
          <Button form="cancelScheduleForm" htmlType="submit" key="submit" type="primary" loading={loading}>
            {t("appointments.actions.cancel")}
          </Button>
        ]}
      >
        <Form
          layout="vertical"
          id="cancelScheduleForm"
          onFinish={async (s) => {
            try {
              await handleLostSaleFinish(s);
            } finally {
              setIsCancelScheduleModalVisible(false);
            }
          }}
        >
          <Form.Item
            name="lost_sale_reason"
            label={t("jobs.fields.lost_sale_reason")}
            rules={[
              {
                required: true
                //message: t("general.validation.required"),
              }
            ]}
          >
            <Select
              options={bodyshop.md_lost_sale_reasons.map((lsr) => ({
                label: lsr,
                value: lsr
              }))}
            />
          </Form.Item>
        </Form>
      </Modal>

      <Dropdown
        menu={menu}
        trigger={["click"]}
        key="changestatus"
        open={dropdownOpen}
        onOpenChange={handleDropdownOpenChange}
      >
        <Button icon={<DownCircleFilled />} iconPlacement="end">
          <span>{t("general.labels.actions")}</span>
        </Button>
      </Dropdown>

      <Popover content={popOverContent} open={visibility} />
    </>
  );
}

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