import { DeleteFilled, PrinterFilled } from "@ant-design/icons";
import { PageHeader } from "@ant-design/pro-layout";
import { useApolloClient, useMutation } from "@apollo/client/react";
import {
  Alert,
  Button,
  Col,
  Divider,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Row,
  Select,
  Space,
  Statistic,
  Switch,
  Typography
} from "antd";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
// import { useNavigate } from 'react-router-dom';
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
import Dinero from "dinero.js";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import DateTimePicker from "../../components/form-date-time-picker/form-date-time-picker.component";
import FormsFieldChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
import CurrencyInput from "../../components/form-items-formatted/currency-form-item.component";
import JobCloseRoGuardContainer from "../../components/job-close-ro-guard/job-close-ro-guard.container";
import JobsScoreboardAdd from "../../components/job-scoreboard-add-button/job-scoreboard-add-button.component";
import JobsCloseAutoAllocate from "../../components/jobs-close-auto-allocate/jobs-close-auto-allocate.component";
import JobsCloseLines from "../../components/jobs-close-lines/jobs-close-lines.component";
import LayoutFormRow from "../../components/layout-form-row/layout-form-row.component";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { generateJobLinesUpdatesForInvoicing } from "../../graphql/jobs-lines.queries";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions.js";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import dayjs from "../../utils/day";
import { bodyshopHasDmsKey, DMS_MAP, getDmsMode } from "../../utils/dmsUtils.js";

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

const mapDispatchToProps = (dispatch) => ({
  insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type })),
  setPrintCenterContext: (context) =>
    dispatch(
      setModalContext({
        context: context,
        modal: "printCenter"
      })
    )
});

export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, setPrintCenterContext, currentUser }) {
  const { t } = useTranslation();
  const [form] = Form.useForm();
  const client = useApolloClient();
  // const history = useNavigate();
  const [closeJob] = useMutation(UPDATE_JOB);
  const [loading, setLoading] = useState(false);
  const notification = useNotification();

  const hasDMSKey = bodyshopHasDmsKey(bodyshop);
  const dmsMode = getDmsMode(bodyshop, "off");
  const isReynoldsMode = dmsMode === DMS_MAP.reynolds;
  const hasEarlyRO = !!(job?.dms_id && job?.dms_customer_id && job?.dms_advisor_id);
  const canSendToDMS = !isReynoldsMode || hasEarlyRO;
  const [showEarlyROModal, setShowEarlyROModal] = useState(false);

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

  const handleFinish = async ({ removefromproduction, ...values }) => {
    setLoading(true);

    // Validate that all joblines have valid IDs
    const joblinesWithIds = values.joblines.filter((jl) => jl && jl.id);
    if (joblinesWithIds.length !== values.joblines.length) {
      notification.error({
        title: t("jobs.errors.invalidjoblines"),
        description: t("jobs.errors.missingjoblineids")
      });
      setLoading(false);
      return;
    }

    const result = await client.mutate({
      mutation: generateJobLinesUpdatesForInvoicing(values.joblines)
    });
    if (result.errors) {
      setLoading(false);
      return; // Abandon the rest of the close.
    }

    const closeResult = await closeJob({
      variables: {
        jobId: job.id,
        job: {
          status: bodyshop.md_ro_statuses.default_invoiced || "",
          date_invoiced: values.date_invoiced,
          actual_in: values.actual_in,
          actual_completion: values.actual_completion,
          actual_delivery: values.actual_delivery,
          kmin: values.kmin,
          kmout: values.kmout,
          dms_allocation: values.dms_allocation,
          admin_clerk: currentUser.email,
          ...(removefromproduction ? { inproduction: false } : {}),
          ...(values.qb_multiple_payers ? { qb_multiple_payers: values.qb_multiple_payers } : {})
        }
      },
      refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
      awaitRefetchQueries: true
    });

    if (!result.errors) {
      // notification["success"]({ message: t("jobs.successes.save") });
      //  form.resetFields();
    } else {
      notification.error({
        title: t("job.errors.saving", {
          error: JSON.stringify(result.errors)
        })
      });
      return; // Abandon the rest of the close.
    }

    if (!closeResult.errors) {
      setLoading(false);

      notification.success({
        title: t("jobs.successes.closed")
      });
      insertAuditTrail({
        jobid: job.id,
        operation: AuditTrailMapping.jobinvoiced(),
        type: "jobinvoiced"
      });
      if (values.masterbypass) {
        insertAuditTrail({
          jobid: job.id,
          operation: AuditTrailMapping.jobclosedwithbypass(),
          type: "jobclosedwithbypass"
        });
      }
      // history(`/manage/jobs/${job.id}`);
    } else {
      setLoading(false);
      notification.error({
        title: t("job.errors.closing", {
          error: JSON.stringify(closeResult.errors)
        })
      });
    }
    form.resetFields();
    form.resetFields();

    setLoading(false);
  };

  return (
    <div>
      <Form
        layout="vertical"
        form={form}
        onFinish={handleFinish}
        initialValues={{
          joblines: job.joblines,
          actual_in: job.actual_in ? dayjs(job.actual_in) : job.scheduled_in && dayjs(job.scheduled_in),
          actual_completion: job.actual_completion
            ? dayjs(job.actual_completion)
            : job.scheduled_completion && dayjs(job.scheduled_completion),
          actual_delivery: job.actual_delivery
            ? dayjs(job.actual_delivery)
            : job.scheduled_delivery && dayjs(job.scheduled_delivery),
          date_invoiced: job.date_invoiced ? dayjs(job.date_invoiced) : dayjs(),
          kmin: job.kmin,
          kmout: job.kmout,
          dms_allocation: job.dms_allocation,
          qb_multiple_payers: job.qb_multiple_payers
        }}
        scrollToFirstError
      >
        <PageHeader
          title={t("jobs.labels.closejob", { ro_number: job.ro_number })}
          extra={
            <Space>
              <JobsCloseAutoAllocate joblines={job.joblines} form={form} disabled={!!job.date_exported || jobRO} />
              <Popconfirm
                onConfirm={() => form.submit()}
                disabled={jobRO}
                okText={t("general.labels.yes")}
                cancelText={t("general.labels.no")}
                title={t("jobs.labels.closeconfirm")}
              >
                <Button loading={loading} type="primary" danger disabled={jobRO}>
                  {t("general.actions.close")}
                </Button>
              </Popconfirm>
              {bodyshopHasDmsKey(bodyshop) && (
                <>
                  {canSendToDMS ? (
                    <Link to={`/manage/dms?jobId=${job.id}`}>
                      <Button disabled={job.date_exported || !jobRO}>{t("jobs.actions.sendtodms")}</Button>
                    </Link>
                  ) : (
                    <Button disabled={job.date_exported || !jobRO} onClick={() => setShowEarlyROModal(true)}>
                      {t("jobs.actions.sendtodms")}
                    </Button>
                  )}
                </>
              )}
              <Button
                onClick={() => {
                  setPrintCenterContext({
                    context: {
                      id: job.id,
                      job: job,
                      type: "job"
                    }
                  });
                }}
                key="printing"
                icon={<PrinterFilled />}
              >
                {t("jobs.actions.printCenter")}
              </Button>
              <JobsScoreboardAdd job={job} disabled={false} />
            </Space>
          }
        />
        <JobCloseRoGuardContainer form={form} job={job} />
        <Space wrap orientation="vertical" style={{ width: "100%" }}>
          <FormsFieldChanged form={form} />
          {!job.actual_in && job.scheduled_in && <Alert type="warning" title={t("jobs.labels.actual_in_inferred")} />}
          {!job.actual_completion && job.scheduled_completion && (
            <Alert type="warning" title={t("jobs.labels.actual_completion_inferred")} />
          )}
          {!job.actual_delivery && job.scheduled_delivery && (
            <Alert type="warning" title={t("jobs.labels.actual_delivery_inferred")} />
          )}
        </Space>
        <LayoutFormRow>
          <Form.Item
            label={t("jobs.fields.actual_in")}
            rules={[
              {
                required: true
              }
            ]}
            name="actual_in"
          >
            <DateTimePicker disabled={jobRO} />
          </Form.Item>
          <Form.Item shouldUpdate>
            {() => {
              return (
                <Form.Item
                  label={t("jobs.fields.actual_completion")}
                  name="actual_completion"
                  rules={[
                    {
                      required: true
                    }
                  ]}
                >
                  <DateTimePicker disabled={jobRO} />
                </Form.Item>
              );
            }}
          </Form.Item>
          <Form.Item
            label={t("jobs.fields.actual_delivery")}
            name="actual_delivery"
            rules={[
              {
                required: true
              }
            ]}
          >
            <DateTimePicker disabled={jobRO} />
          </Form.Item>
          <Form.Item
            label={t("jobs.fields.date_invoiced")}
            name="date_invoiced"
            rules={[
              {
                required: true
              },
              () => ({
                validator(_, value) {
                  if (!bodyshop.cdk_dealerid) return Promise.resolve();
                  if (!value || dayjs(value).isSameOrAfter(dayjs(), "day")) {
                    return Promise.resolve();
                  }
                  return Promise.reject(new Error(t("jobs.labels.dms.invoicedatefuture")));
                }
              }),
              () => ({
                validator(_, value) {
                  if (ClosingPeriod.treatment === "on" && bodyshop.accountingconfig.ClosingPeriod) {
                    if (
                      dayjs(value).isSameOrAfter(dayjs(bodyshop.accountingconfig.ClosingPeriod[0]).startOf("day")) &&
                      dayjs(value).isSameOrBefore(dayjs(bodyshop.accountingconfig.ClosingPeriod[1]).endOf("day"))
                    ) {
                      return Promise.resolve();
                    } else {
                      return Promise.reject(new Error(t("jobs.labels.closingperiod")));
                    }
                  } else {
                    return Promise.resolve();
                  }
                }
              })
            ]}
          >
            <DateTimePicker disabled={jobRO} onlyFuture={!!bodyshop.cdk_dealerid} />
          </Form.Item>
          {!jobRO && job.inproduction && (
            <Form.Item
              label={t("jobs.actions.removefromproduction")}
              name="removefromproduction"
              valuePropName="checked"
            >
              <Switch />
            </Form.Item>
          )}
          {hasDMSKey && (
            <Form.Item
              label={t("jobs.fields.kmin")}
              name="kmin"
              rules={[
                {
                  required: true
                }
              ]}
            >
              <InputNumber precision={0} disabled={jobRO} />
            </Form.Item>
          )}
          {hasDMSKey && (
            <Form.Item
              label={t("jobs.fields.kmout")}
              name="kmout"
              dependencies={["kmin"]}
              hasFeedback
              rules={[
                {
                  required: true
                },
                ({ getFieldValue }) => ({
                  validator(_, value) {
                    if (!value || getFieldValue("kmin") <= value) {
                      return Promise.resolve();
                    }

                    return Promise.reject(new Error(t("jobs.labels.dms.kmoutnotgreaterthankmin")));
                  }
                })
              ]}
            >
              <InputNumber precision={0} disabled={jobRO} />
            </Form.Item>
          )}
          {hasDMSKey && (
            <Form.Item
              label={t("jobs.fields.dms_allocation")}
              name="dms_allocation"
              rules={[
                {
                  required: true
                }
              ]}
            >
              <Input disabled />
            </Form.Item>
          )}
        </LayoutFormRow>

        {Qb_Multi_Ar.treatment === "on" && (
          <>
            <Divider>{t("jobs.labels.multipayers")}</Divider>
            <Row gutter={[16, 16]}>
              <Col lg={8} md={24}>
                <Form.List
                  name={["qb_multiple_payers"]}
                  rules={[
                    () => ({
                      validator() {
                        let totalAllocated = Dinero();

                        const payers = form.getFieldValue("qb_multiple_payers");
                        payers &&
                          payers.forEach((payer) => {
                            totalAllocated = totalAllocated.add(
                              Dinero({
                                amount: Math.round((payer?.amount || 0) * 100)
                              })
                            );
                          });
                        const discrep = job.job_totals
                          ? Dinero(job.job_totals.totals.total_repairs).subtract(totalAllocated)
                          : Dinero();
                        return discrep.getAmount() >= 0
                          ? Promise.resolve()
                          : Promise.reject(new Error(t("jobs.labels.additionalpayeroverallocation")));
                      }
                    })
                  ]}
                >
                  {(fields, { add, remove }) => {
                    return (
                      <div>
                        {fields.map((field, index) => (
                          <Form.Item key={field.key}>
                            <Space>
                              <Form.Item
                                label={t("jobs.fields.qb_multiple_payers.name")}
                                key={`${index}name`}
                                name={[field.name, "name"]}
                                rules={[
                                  {
                                    required: true
                                  }
                                ]}
                              >
                                <Select
                                  style={{ minWidth: "12rem" }}
                                  disabled={jobRO}
                                  options={bodyshop.md_ins_cos.map((s) => ({
                                    key: s.name,
                                    value: s.name,
                                    label: s.name
                                  }))}
                                />
                              </Form.Item>

                              <Form.Item
                                label={t("jobs.fields.qb_multiple_payers.amount")}
                                key={`${index}amount`}
                                name={[field.name, "amount"]}
                                rules={[
                                  {
                                    required: true
                                  }
                                ]}
                              >
                                <CurrencyInput min={0} disabled={jobRO} />
                              </Form.Item>

                              <DeleteFilled
                                disabled={jobRO}
                                onClick={() => {
                                  if (!jobRO) {
                                    remove(field.name);
                                  }
                                }}
                              />
                            </Space>
                          </Form.Item>
                        ))}
                        <Form.Item>
                          <Button
                            disabled={jobRO}
                            onClick={() => {
                              add();
                            }}
                            style={{ width: "100%" }}
                          >
                            {t("jobs.actions.dms.addpayer")}
                          </Button>
                        </Form.Item>
                      </div>
                    );
                  }}
                </Form.List>
              </Col>
              <Col lg={16} md={24}>
                <Form.Item shouldUpdate>
                  {() => {
                    //Perform Calculation to determine discrepancy.
                    let totalAllocated = Dinero();

                    const payers = form.getFieldValue("qb_multiple_payers");
                    payers &&
                      payers.forEach((payer) => {
                        totalAllocated = totalAllocated.add(
                          Dinero({
                            amount: Math.round((payer?.amount || 0) * 100)
                          })
                        );
                      });
                    const discrep = job.job_totals
                      ? Dinero(job.job_totals.totals.total_repairs).subtract(totalAllocated)
                      : Dinero();
                    return (
                      <Space size="large" wrap align="center">
                        <Statistic
                          title={t("jobs.labels.total_cust_payable")}
                          value={(job.job_totals ? Dinero(job.job_totals.totals.custPayable) : Dinero()).toFormat()}
                        />
                        <Divider orientation="vertical" />
                        <Statistic
                          title={t("jobs.labels.total_repairs")}
                          value={(job.job_totals ? Dinero(job.job_totals.totals.total_repairs) : Dinero()).toFormat()}
                        />
                        <Typography.Title>-</Typography.Title>
                        <Statistic title={t("jobs.labels.dms.totalallocated")} value={totalAllocated.toFormat()} />
                        <Typography.Title>=</Typography.Title>
                        <Statistic
                          title={t("jobs.labels.pimraryamountpayable")}
                          styles={{
                            content: {
                              color: discrep.getAmount() >= 0 ? "green" : "red"
                            }
                          }}
                          value={discrep.toFormat()}
                        />
                      </Space>
                    );
                  }}
                </Form.Item>
              </Col>
            </Row>
          </>
        )}
        <Divider />
        <JobsCloseLines job={job} />
      </Form>

      {/* Early RO Required Modal */}
      <Modal
        open={showEarlyROModal}
        onCancel={() => setShowEarlyROModal(false)}
        footer={null}
        title={
          <Space>
            <Typography.Text type="warning" style={{ fontSize: "1.2em" }}>
              ⚠️
            </Typography.Text>
            <span>{t("dms.errors.earlyrorequired")}</span>
          </Space>
        }
      >
        <Space orientation="vertical" size="large" style={{ width: "100%" }}>
          <Typography.Paragraph>{t("dms.errors.earlyrorequired.message")}</Typography.Paragraph>
          <Link to={`/manage/jobs/${job.id}/admin`}>
            <Button type="primary" block onClick={() => setShowEarlyROModal(false)}>
              {t("general.actions.gotoadmin")}
            </Button>
          </Link>
        </Space>
      </Modal>
    </div>
  );
}

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