import { useApolloClient, useMutation } from "@apollo/client";
import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
import { Button, Form, Modal, notification } from "antd";
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { GET_JOB_INFO_FOR_STRIPE } from "../../graphql/jobs.queries";
import {
  INSERT_NEW_PAYMENT,
  UPDATE_PAYMENT,
} from "../../graphql/payments.queries";
import { setEmailOptions } from "../../redux/email/email.actions";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectPayment } from "../../redux/modals/modals.selectors";
import {
  selectBodyshop,
  selectCurrentUser,
} from "../../redux/user/user.selectors";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
import PaymentForm from "../payment-form/payment-form.component";

const mapStateToProps = createStructuredSelector({
  paymentModal: selectPayment,
  bodyshop: selectBodyshop,
  currentUser: selectCurrentUser,
});

const mapDispatchToProps = (dispatch) => ({
  setEmailOptions: (e) => dispatch(setEmailOptions(e)),
  toggleModalVisible: () => dispatch(toggleModalVisible("payment")),
});

function PaymentModalContainer({
  paymentModal,
  toggleModalVisible,
  bodyshop,
  currentUser,
  setEmailOptions,
}) {
  const [form] = Form.useForm();
  const [enterAgain, setEnterAgain] = useState(false);
  const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
  const [updatePayment] = useMutation(UPDATE_PAYMENT);
  const client = useApolloClient();
  const stripe = useStripe();
  const elements = useElements();
  const { t } = useTranslation();
  const { context, actions, visible } = paymentModal;

  const [loading, setLoading] = useState(false);
  const stripeStateArr = useState({
    error: null,
    cardComplete: false,
  });
  const stripeState = stripeStateArr[0];

  const cardValid = !!!stripeState.error && stripeState.cardComplete;

  const handleFinish = async (values) => {
    const { useStripe, sendby, ...paymentObj } = values;
    if (useStripe && !cardValid) return;

    if ((useStripe && !stripe) || !elements) {
      // Stripe.js has not yet loaded.
      // Make sure to disable form submission until Stripe.js has loaded.
      return;
    }

    setLoading(true);

    try {
      let stripePayment;
      if (useStripe && bodyshop.stripe_acct_id) {
        logImEXEvent("payment_stripe_attempt");

        const secretKey = await axios.post("/stripe/payment", {
          amount: Math.round(values.amount * 100),
          stripe_acct_id: bodyshop.stripe_acct_id,
        });

        const { data } = await client.query({
          query: GET_JOB_INFO_FOR_STRIPE,
          variables: { jobid: values.jobid },
        });

        stripePayment = await stripe.confirmCardPayment(
          secretKey.data.clientSecret,
          {
            payment_method: {
              card: elements.getElement(CardElement),
              billing_details: {
                name: `${data.jobs_by_pk.ownr_fn || ""} ${
                  data.jobs_by_pk.ownr_ln || ""
                } ${data.jobs_by_pk.ownr_co_nm || ""}`,
                email: data.jobs_by_pk.ownr_ea,
                phone: data.jobs_by_pk.ownr_ph1,
              },
            },
          }
        );

        if (stripePayment.paymentIntent.status === "succeeded") {
          notification["success"]({ message: t("payments.successes.stripe") });
        } else {
          notification["error"]({ message: t("payments.errors.stripe") });
          throw new Error();
        }
      }
      logImEXEvent("payment_insert");

      if (!context || (context && !context.id)) {
        const newPayment = await insertPayment({
          variables: {
            paymentInput: {
              ...paymentObj,
              stripeid:
                stripePayment &&
                stripePayment.paymentIntent &&
                stripePayment.paymentIntent.id,
            },
          },
        });

        if (!!!newPayment.errors) {
          notification["success"]({ message: t("payments.successes.payment") });
        } else {
          notification["error"]({ message: t("payments.errors.payment") });
        }
        const Templates = TemplateList("payment");
        if (sendby !== "none") {
          GenerateDocument(
            {
              name: Templates.payment_receipt.key,
              variables: {
                id: newPayment.data.insert_payments.returning[0].id,
              },
            },
            {
              // to: [appData.email],
              replyTo: bodyshop.email,
              subject: Templates.payment_receipt.subject,
            },
            sendby === "email" ? "e" : "p",
            paymentObj.jobid
          );
        }
      } else {
        const updatedPayment = await updatePayment({
          variables: {
            paymentId: context.id,
            payment: paymentObj,
          },
        });

        if (!!!updatedPayment.errors) {
          notification["success"]({ message: t("payments.successes.payment") });
        } else {
          notification["error"]({ message: t("payments.errors.payment") });
        }
      }

      if (actions.refetch) actions.refetch();
      if (enterAgain) {
        const prev = form.getFieldsValue(["date"]);

        form.resetFields();
        form.setFieldsValue(prev);
      } else {
        toggleModalVisible();
      }
      setEnterAgain(false);
    } catch (error) {
      console.log("error", error);
    } finally {
      setEnterAgain(false);
      setLoading(false);
    }
  };

  const handleCancel = () => {
    toggleModalVisible();
  };

  useEffect(() => {
    if (visible) form.resetFields();
  }, [visible, form, context]);

  useEffect(() => {
    if (enterAgain) form.submit();
  }, [enterAgain, form]);

  return (
    <Modal
      title={
        !context || (context && !context.id)
          ? t("payments.labels.new")
          : t("payments.labels.edit")
      }
      visible={visible}
      okText={t("general.actions.save")}
      onOk={() => form.submit()}
      width="50%"
      onCancel={handleCancel}
      okButtonProps={{
        loading: loading,
      }}
      afterClose={() => form.resetFields()}
      footer={
        <span>
          <Button onClick={handleCancel}>{t("general.actions.cancel")}</Button>
          <Button loading={loading} onClick={() => form.submit()}>
            {t("general.actions.save")}
          </Button>
          {paymentModal.context && paymentModal.context.id ? null : (
            <Button
              type="primary"
              loading={loading}
              onClick={() => {
                setEnterAgain(true);
              }}
            >
              {t("general.actions.saveandnew")}
            </Button>
          )}
        </span>
      }
    >
      <Form
        onFinish={handleFinish}
        autoComplete={"off"}
        form={form}
        layout="vertical"
        initialValues={context || {}}
      >
        <PaymentForm
          form={form}
          stripeStateArr={stripeStateArr}
          disabled={context && context.stripeid}
        />
      </Form>
    </Modal>
  );
}

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

// const pr = stripe.paymentRequest({
//   country: "CA",
//   currency: "CAD",
//   total: {
//     label: "Demo total",
//     amount: 1099,
//   },
//   requestPayerName: true,
//   requestPayerEmail: true,
// });
// console.log("handleFinish -> pr", pr);
