import Icon, { UploadOutlined } from "@ant-design/icons";
import { useApolloClient } from "@apollo/client/react";
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
import { Alert, Divider, Form, Input, Select, Space, Statistic, Switch, Upload } from "antd";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { MdOpenInNew } from "react-icons/md";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { CHECK_BILL_INVOICE_NUMBER } from "../../graphql/bills.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import dayjs from "../../utils/day";
import { bodyshopHasDmsKey } from "../../utils/dmsUtils.js";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import AlertComponent from "../alert/alert.component";
import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import JobSearchSelect from "../job-search-select/job-search-select.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
import BillFormLines from "./bill-form.lines.component";
import { CalculateBillTotal } from "./bill-form.totals.utility";

const mapStateToProps = createStructuredSelector({
  bodyshop: selectBodyshop
});
const mapDispatchToProps = () => ({});

export function BillFormComponent({
  bodyshop,
  disabled,
  form,
  vendorAutoCompleteOptions,
  lineData,
  responsibilityCenters,
  loadLines,
  billEdit,
  disableInvNumber,
  job,
  loadOutstandingReturns,
  loadInventory,
  preferredMake,
  disableInHouse,
  isAiScan
}) {
  const { t } = useTranslation();
  const client = useApolloClient();
  const [discount, setDiscount] = useState(0);
  const notification = useNotification();
  const jobIdFormWatch = Form.useWatch("jobid", form);
  const vendorIdFormWatch = Form.useWatch("vendorid", form);

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

  const handleVendorSelect = (props, opt) => {
    setDiscount(opt.discount);

    opt &&
      !billEdit &&
      loadOutstandingReturns({
        variables: {
          jobId: form.getFieldValue("jobid"),
          vendorId: opt.value
        }
      });
  };

  const handleFederalTaxExemptSwitchToggle = (checked) => {
    // Early gate
    if (!checked) return;
    const values = form.getFieldsValue("billlines");
    // Gate bill lines
    if (!values?.billlines?.length) return;

    const billlines = values.billlines.map((b) => {
      b.applicable_taxes.federal = false;
      return b;
    });
    form.setFieldsValue({ billlines });
  };

  useEffect(() => {
    if (job) form.validateFields(["is_credit_memo"]);
  }, [job, form]);

  useEffect(() => {
    const vendorId = form.getFieldValue("vendorid");
    if (vendorId && vendorAutoCompleteOptions) {
      const matchingVendors = vendorAutoCompleteOptions.filter((v) => v.id === vendorId);
      if (matchingVendors.length === 1) {
        setDiscount(matchingVendors[0].discount);
      }
    }
    const jobId = form.getFieldValue("jobid");
    if (jobId) {
      loadLines({ variables: { id: jobId } });
      if (form.getFieldValue("is_credit_memo") && vendorId && !billEdit) {
        loadOutstandingReturns({
          variables: {
            jobId: jobId,
            vendorId: vendorId
          }
        });
      }
    }

    if (vendorId === bodyshop.inhousevendorid && !billEdit) {
      loadInventory({ variables: {} });
    }
  }, [
    form,
    vendorIdFormWatch,
    billEdit,
    loadOutstandingReturns,
    loadInventory,
    setDiscount,
    vendorAutoCompleteOptions,
    loadLines,
    bodyshop.inhousevendorid
  ]);

  useEffect(() => {
    // When the jobid is set by AI scan, we need to reload the lines. This prevents having to hoist the apollo query.
    if (jobIdFormWatch !== null) {
      if (form.getFieldValue("jobid") !== null && form.getFieldValue("jobid") !== undefined) {
        loadLines({ variables: { id: form.getFieldValue("jobid") } });
        if (form.getFieldValue("vendorid") !== null && form.getFieldValue("vendorid") !== undefined) {
          loadOutstandingReturns({
            variables: {
              jobId: form.getFieldValue("jobid"),
              vendorId: form.getFieldValue("vendorid")
            }
          });
        }
      }
    }
  }, [jobIdFormWatch, form]);

  return (
    <div>
      <FormFieldsChanged form={form} />
      <Form.Item hidden name="isinhouse" valuePropName="checked">
        <Switch />
      </Form.Item>
      <LayoutFormRow grow>
        <Form.Item
          name="jobid"
          label={t("bills.fields.ro_number")}
          rules={[
            {
              required: true
              //message: t("general.validation.required"),
            }
          ]}
        >
          <JobSearchSelect
            disabled={billEdit || disabled}
            convertedOnly
            notExported={false}
            onBlur={() => {
              if (form.getFieldValue("jobid") !== null && form.getFieldValue("jobid") !== undefined) {
                loadLines({ variables: { id: form.getFieldValue("jobid") } });
                if (form.getFieldValue("vendorid") !== null && form.getFieldValue("vendorid") !== undefined) {
                  loadOutstandingReturns({
                    variables: {
                      jobId: form.getFieldValue("jobid"),
                      vendorId: form.getFieldValue("vendorid")
                    }
                  });
                }
              }
            }}
          />
        </Form.Item>
        <Form.Item
          label={t("bills.fields.vendor")}
          name="vendorid"
          // style={{ display: billEdit ? "none" : null }}
          rules={[
            {
              required: true
              //message: t("general.validation.required"),
            },
            ({ getFieldValue }) => ({
              validator(rule, value) {
                if (value && !getFieldValue(["isinhouse"]) && value === bodyshop.inhousevendorid) {
                  return Promise.reject(t("bills.validation.manualinhouse"));
                }
                return Promise.resolve();
              }
            })
          ]}
        >
          <VendorSearchSelect
            disabled={disabled || disableInHouse}
            options={vendorAutoCompleteOptions}
            preferredMake={preferredMake}
            onSelect={handleVendorSelect}
          />
        </Form.Item>
      </LayoutFormRow>
      {job &&
        job.ious &&
        job.ious.length > 0 &&
        job.ious.map((iou) => (
          <Alert
            key={iou.id}
            type="warning"
            title={
              <Space>
                {t("bills.labels.iouexists")}
                <Link target="_blank" rel="noopener noreferrer" to={`/manage/jobs/${iou.id}?tab=repairdata`}>
                  <Space>
                    {iou.ro_number}
                    <Icon component={MdOpenInNew} />
                  </Space>
                </Link>
              </Space>
            }
          />
        ))}
      <LayoutFormRow>
        <Form.Item
          label={t("bills.fields.invoice_number")}
          name="invoice_number"
          validateTrigger="onBlur"
          hasFeedback
          rules={[
            {
              required: true
              //message: t("general.validation.required"),
            },
            ({ getFieldValue }) => ({
              async validator(rule, value) {
                const vendorid = getFieldValue("vendorid");
                if (vendorid && value) {
                  const response = await client.query({
                    query: CHECK_BILL_INVOICE_NUMBER,
                    variables: {
                      invoice_number: value,
                      vendorid: vendorid
                    }
                  });

                  if (response.data.bills_aggregate.aggregate.count === 0) {
                    return Promise.resolve();
                  } else if (
                    response.data.bills_aggregate.nodes.length === 1 &&
                    response.data.bills_aggregate.nodes[0].id === form.getFieldValue("id")
                  ) {
                    return Promise.resolve();
                  }
                  return Promise.reject(t("bills.validation.unique_invoice_number"));
                } else {
                  return Promise.resolve();
                }
              }
            })
          ]}
        >
          <Input disabled={disabled || disableInvNumber || disableInHouse} />
        </Form.Item>
        <Form.Item
          label={t("bills.fields.date")}
          name="date"
          rules={[
            {
              required: true
              //message: t("general.validation.required"),
            },
            () => ({
              validator(rule, value) {
                if (ClosingPeriod.treatment === "on" && bodyshop.accountingconfig.ClosingPeriod) {
                  if (
                    dayjs(value)
                      .startOf("day")
                      .isSameOrAfter(dayjs(bodyshop.accountingconfig.ClosingPeriod[0]).startOf("day")) &&
                    dayjs(value)
                      .startOf("day")
                      .isSameOrBefore(dayjs(bodyshop.accountingconfig.ClosingPeriod[1]).endOf("day"))
                  ) {
                    return Promise.resolve();
                  } else {
                    return Promise.reject(t("bills.validation.closingperiod"));
                  }
                } else {
                  return Promise.resolve();
                }
              }
            })
          ]}
        >
          <DateTimePicker isDateOnly disabled={disabled} />
        </Form.Item>
        <Form.Item
          label={t("bills.fields.is_credit_memo")}
          name="is_credit_memo"
          valuePropName="checked"
          rules={[
            ({ getFieldValue }) => ({
              validator(rule, value) {
                if (value === true && getFieldValue("jobid") && getFieldValue("vendorid")) {
                  //Removed as this would cause an additional reload when validating the form on submit and clear the values.
                  // loadOutstandingReturns({
                  //   variables: {
                  //     jobId: form.getFieldValue("jobid"),
                  //     vendorId: form.getFieldValue("vendorid"),
                  //   },
                  // });
                }

                if (
                  !bodyshop.bill_allow_post_to_closed &&
                  job &&
                  (job.status === bodyshop.md_ro_statuses.default_invoiced ||
                    job.status === bodyshop.md_ro_statuses.default_exported ||
                    job.status === bodyshop.md_ro_statuses.default_void) &&
                  (value === false || !value)
                ) {
                  return Promise.reject(t("bills.labels.onlycmforinvoiced"));
                }

                return Promise.resolve();
              }
            })
          ]}
        >
          <Switch />
        </Form.Item>
        <Form.Item
          label={t("bills.fields.total")}
          name="total"
          rules={[
            {
              required: true
              //message: t("general.validation.required"),
            }
          ]}
        >
          <CurrencyInput min={0} disabled={disabled} />
        </Form.Item>
        {!billEdit && (
          <Form.Item label={t("bills.fields.allpartslocation")} name="location">
            <Select 
              style={{ width: "10rem" }} 
              disabled={disabled} 
              allowClear
              options={bodyshop.md_parts_locations.map((loc) => ({ value: loc, label: loc }))}
            />
          </Form.Item>
        )}
      </LayoutFormRow>
      <LayoutFormRow>
        {InstanceRenderManager({
          imex: (
            <Form.Item span={3} label={t("bills.fields.federal_tax_rate")} name="federal_tax_rate">
              <CurrencyInput min={0} disabled={disabled} />
            </Form.Item>
          )
        })}
        <Form.Item span={3} label={t("bills.fields.state_tax_rate")} name="state_tax_rate">
          <CurrencyInput min={0} disabled={disabled} />
        </Form.Item>
        {InstanceRenderManager({
          imex: (
            <>
              <Form.Item span={3} label={t("bills.fields.local_tax_rate")} name="local_tax_rate">
                <CurrencyInput min={0} />
              </Form.Item>
              {bodyshopHasDmsKey(bodyshop) ? (
                <Form.Item span={2} label={t("bills.labels.federal_tax_exempt")} name="federal_tax_exempt">
                  <Switch onChange={handleFederalTaxExemptSwitchToggle} />
                </Form.Item>
              ) : null}
            </>
          )
        })}
        <Form.Item shouldUpdate span={13}>
          {() => {
            const values = form.getFieldsValue([
              "billlines",
              "total",
              "federal_tax_rate",
              "state_tax_rate",
              "local_tax_rate"
            ]);
            let totals;
            if (!!values.total && !!values.billlines && values.billlines.length > 0) {
              try {
                totals = CalculateBillTotal(values);
              } catch (error) {
                notification.error({
                  title: t("bills.errors.calculating_totals"),
                  message: error.message || t("bills.errors.calculating_totals_generic"),
                  key: "bill_totals_calculation_error"
                });
              }
            }

            if (totals) {
              return (
                // TODO: Align is not correct
                // eslint-disable-next-line react/no-unknown-property
                <div align="right">
                  <Space size="large" wrap>
                    <Statistic title={t("bills.labels.subtotal")} value={totals.subtotal.toFormat()} precision={2} />
                    {InstanceRenderManager({
                      imex: (
                        <Statistic
                          title={t("bills.labels.federal_tax")}
                          value={totals.federalTax.toFormat()}
                          precision={2}
                        />
                      )
                    })}
                    <Statistic title={t("bills.labels.state_tax")} value={totals.stateTax.toFormat()} precision={2} />
                    {InstanceRenderManager({
                      imex: (
                        <Statistic
                          title={t("bills.labels.local_tax")}
                          value={totals.localTax.toFormat()}
                          precision={2}
                        />
                      )
                    })}
                    <Statistic
                      title={t("bills.labels.entered_total")}
                      value={totals.enteredTotal.toFormat()}
                      precision={2}
                    />
                    <Statistic
                      title={t("bills.labels.bill_total")}
                      value={totals.invoiceTotal.toFormat()}
                      precision={2}
                    />
                    <Statistic
                      title={t("bills.labels.discrepancy")}
                      styles={{
                        content: {
                          color: totals.discrepancy.getAmount() === 0 ? "green" : "red"
                        }
                      }}
                      value={totals.discrepancy.toFormat()}
                      precision={2}
                    />
                  </Space>
                  {form.getFieldValue("is_credit_memo") ? (
                    <AlertComponent type="warning" title={t("bills.labels.enteringcreditmemo")} />
                  ) : null}
                </div>
              );
            }
            return null;
          }}
        </Form.Item>
      </LayoutFormRow>
      <Divider titlePlacement="left">{t("bills.labels.bill_lines")}</Divider>

      {Extended_Bill_Posting.treatment === "on" ? (
        <BillFormLinesExtended
          lineData={lineData}
          discount={discount}
          form={form}
          responsibilityCenters={responsibilityCenters}
          disabled={disabled}
        />
      ) : (
        <BillFormLines
          lineData={lineData}
          discount={discount}
          form={form}
          responsibilityCenters={responsibilityCenters}
          disabled={disabled}
          billEdit={billEdit}
          isAiScan={isAiScan}
        />
      )}
      <Divider titlePlacement="left" style={{ display: billEdit ? "none" : null }}>
        {t("documents.labels.upload")}
      </Divider>
      <Form.Item
        name="upload"
        label="Upload"
        style={{ display: billEdit ? "none" : null }}
        valuePropName="fileList"
        getValueFromEvent={(e) => {
          if (Array.isArray(e)) {
            return e;
          }
          return e?.fileList;
        }}
      >
        <Upload.Dragger multiple={true} name="logo" beforeUpload={() => false} listType="picture">
          <>
            <p className="ant-upload-drag-icon">
              <UploadOutlined />
            </p>
            <p className="ant-upload-text">Click or drag files to this area to upload.</p>
          </>
        </Upload.Dragger>
      </Form.Item>
    </div>
  );
}

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