import { useHost, useLocale, useMutation, useParent, useParentQueryValue, useParentValue, useUserIdentity, } from "@saasquatch/component-boilerplate";
import { useEffect, useRef, useState } from "@saasquatch/universal-hooks";
import { gql } from "graphql-request";
import JSONPointer from "jsonpointer";
import { intl } from "../../../global/global";
import { VERIFICATION_EVENT_KEY } from "../../sqm-widget-verification/keys";
import { FINANCE_NETWORK_SETTINGS_NAMESPACE, SORTED_COUNTRIES_NAMESPACE, TAX_CONTEXT_NAMESPACE, TAX_FORM_CONTEXT_NAMESPACE, USER_QUERY_NAMESPACE, } from "../data";
import { TAX_FORM_UPDATED_EVENT_KEY } from "../eventKeys";
// Hardcoded in Impact backend
export const paypalFeeMap = {
  USD: "USD20.00",
  GBP: "GBP30.00",
  EUR: "EUR35.00",
  AUD: "AUD60.00",
  CAD: "CAD50.00",
  NZD: "NZD60.00",
  HKD: "HKD320.00",
  DKK: "DKK250.00",
  ILS: "ILS160.00",
  MXN: "MXN600.00",
  RUB: "RUB1200.00",
  PHP: "PHP2000.00",
  JPY: "JPY2000.00",
};
const ACH_PAYMENT_METHOD = 3;
const WIRE_PAYMENT_METHOD = 5;
const PAYPAL_PAYMENT_METHOD = 7;
export function getFormInputs({ bitset, formMap }) {
  // Convert bitset to binary representation
  const binary = bitset.toString(2).padStart(Object.keys(formMap).length, "0");
  // Reverse to match order of docs
  // https://docs.google.com/document/d/1db8BnXK4NXN8LcX1U0-GBcnq57X3_XKmFBZijLOIYt4
  const inputFields = [...binary].reverse().reduce((agg, num, idx) => {
    if (!Number(num) || !formMap[idx])
      return agg;
    return [...agg, formMap[idx]];
  }, []);
  return inputFields;
}
const SAVE_WITHDRAWAL_SETTINGS = gql `
  mutation setImpactPublisherWithdrawalSettings(
    $setImpactPublisherWithdrawalSettingsInput: SetImpactPublisherWithdrawalSettingsInput!
  ) {
    setImpactPublisherWithdrawalSettings(
      setImpactPublisherWithdrawalSettingsInput: $setImpactPublisherWithdrawalSettingsInput
    ) {
      success
      validationErrors {
        field
        message
      }
    }
  }
`;
const UPDATE_WITHDRAWAL_SETTINGS = gql `
  mutation updateImpactPublisherWithdrawalSettings(
    $updateImpactPublisherWithdrawalSettingsInput: UpdateImpactPublisherWithdrawalSettingsInput!
  ) {
    updateImpactPublisherWithdrawalSettings(
      updateImpactPublisherWithdrawalSettingsInput: $updateImpactPublisherWithdrawalSettingsInput
    ) {
      success
      validationErrors {
        field
        message
      }
    }
  }
`;
function getPaymentMethod(paymentOption) {
  if (paymentOption.defaultFinancePaymentMethodId === 3 ||
    paymentOption.defaultFinancePaymentMethodId === 5)
    return "BANK_TRANSFER";
  if (paymentOption.defaultFinancePaymentMethodId === 7)
    return "PAYPAL";
  return "";
}
function parseImpactThreshold(threshold) {
  // Impact returns a "10.00" decimal string for threshold
  const parsed = Number.parseInt(threshold);
  if (isNaN(parsed))
    return undefined;
  return parsed.toString();
}
export function useBankingInfoForm(props) {
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
  const host = useHost();
  const locale = useLocale();
  const user = useUserIdentity();
  const [step, setStep] = useParent(TAX_CONTEXT_NAMESPACE);
  const context = useParentValue(TAX_FORM_CONTEXT_NAMESPACE);
  const countries = useParentValue(SORTED_COUNTRIES_NAMESPACE);
  const formRef = useRef(null);
  const { data: paymentOptionsData, loading: paymentOptionsLoading, errors: paymentOptionsError, } = useParentQueryValue(FINANCE_NETWORK_SETTINGS_NAMESPACE);
  const { data: userData, refetch, errors: userError, } = useParentQueryValue(USER_QUERY_NAMESPACE);
  const [saveWithdrawalSettings] = useMutation(SAVE_WITHDRAWAL_SETTINGS);
  const [updateWithdrawalSettings] = useMutation(UPDATE_WITHDRAWAL_SETTINGS);
  const [showVerification, setShowVerification] = useState(false);
  const [currentFormData, setCurrentFormData] = useState(null);
  const [formState, setFormState] = useState({});
  const [currentPaymentOption, setCurrentPaymentOption] = useState(null);
  const [loading, setLoading] = useState(false);
  const [errors, setErrors] = useState({});
  const [_paymentMethodChecked, _setPaymentMethodChecked] = useState(undefined);
  const [paymentScheduleChecked, setPaymentScheduleChecked] = useState(undefined);
  const [countrySearch, setCountrySearch] = useState("");
  const [filteredCountries, setFilteredCountries] = useState(countries || []);
  const [showModal, setShowModal] = useState(false);
  const currency = ((_c = (_b = (_a = userData === null || userData === void 0 ? void 0 : userData.user) === null || _a === void 0 ? void 0 : _a.impactConnection) === null || _b === void 0 ? void 0 : _b.publisher) === null || _c === void 0 ? void 0 : _c.currency) || "";
  const isPartner = !!((_f = (_e = (_d = userData === null || userData === void 0 ? void 0 : userData.user) === null || _d === void 0 ? void 0 : _d.impactConnection) === null || _e === void 0 ? void 0 : _e.publisher) === null || _f === void 0 ? void 0 : _f.withdrawalSettings);
  const feeCap = paypalFeeMap[currency] || "";
  const paymentOptions = (_g = paymentOptionsData === null || paymentOptionsData === void 0 ? void 0 : paymentOptionsData.impactFinanceNetworkSettings) === null || _g === void 0 ? void 0 : _g.data;
  const paymentMethodFeeMap = {
    [ACH_PAYMENT_METHOD]: props.eftWithdrawalLabel,
    [WIRE_PAYMENT_METHOD]: intl.formatMessage({
      id: "fxWireText",
      defaultMessage: props.fxWireProcessingFeeLabel,
    }, {
      currency: currency,
      defaultFxFee: (currentPaymentOption === null || currentPaymentOption === void 0 ? void 0 : currentPaymentOption.defaultFxFee) || 0,
    }),
  };
  const paymentMethodFeeLabel = paymentMethodFeeMap[currentPaymentOption === null || currentPaymentOption === void 0 ? void 0 : currentPaymentOption.defaultFinancePaymentMethodId];
  const hasPayPal = !!(paymentOptions === null || paymentOptions === void 0 ? void 0 : paymentOptions.find((option) => option.defaultFinancePaymentMethodId === PAYPAL_PAYMENT_METHOD));
  const paymentMethodChecked = !hasPayPal
    ? "toBankAccount"
    : _paymentMethodChecked;
  useEffect(() => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j;
    if (!userData)
      return;
    if (!paymentOptions)
      return;
    const publisherCountry = (_c = (_b = (_a = userData === null || userData === void 0 ? void 0 : userData.user) === null || _a === void 0 ? void 0 : _a.impactConnection) === null || _b === void 0 ? void 0 : _b.publisher) === null || _c === void 0 ? void 0 : _c.countryCode;
    const withdrawalSettings = (_f = (_e = (_d = userData === null || userData === void 0 ? void 0 : userData.user) === null || _d === void 0 ? void 0 : _d.impactConnection) === null || _e === void 0 ? void 0 : _e.publisher) === null || _f === void 0 ? void 0 : _f.withdrawalSettings;
    // Use currentPaymentOption and initialise form with userData
    let initialData = {
      bankCountry: (withdrawalSettings === null || withdrawalSettings === void 0 ? void 0 : withdrawalSettings.bankCountry) || publisherCountry,
      paymentMethod: "BANK_TRANSFER",
    };
    if (withdrawalSettings && ((_j = (_h = (_g = userData.user) === null || _g === void 0 ? void 0 : _g.impactConnection) === null || _h === void 0 ? void 0 : _h.publisher) === null || _j === void 0 ? void 0 : _j.brandedSignup)) {
      initialData = {
        ...initialData,
        paymentMethod: withdrawalSettings.paymentMethod,
        paypalEmailAddress: withdrawalSettings.paypalEmailAddress,
        paymentSchedulingType: withdrawalSettings.paymentSchedulingType,
        paymentThreshold: parseImpactThreshold(withdrawalSettings.paymentThreshold),
        paymentDay: withdrawalSettings.paymentDay,
      };
    }
    const currentPaymentOption = paymentOptions === null || paymentOptions === void 0 ? void 0 : paymentOptions.find((paymentOption) => {
      if (initialData.paymentMethod === "PAYPAL") {
        if (paymentOption.defaultFinancePaymentMethodId === 7) {
          return true;
        }
      }
      else {
        if (paymentOption.countryCode === initialData.bankCountry)
          return true;
      }
      return false;
    });
    if (initialData.paymentMethod !== "PAYPAL")
      updateBankCountry(currentPaymentOption === null || currentPaymentOption === void 0 ? void 0 : currentPaymentOption.countryCode);
    setPaymentMethodChecked(initialData.paymentMethod === "PAYPAL"
      ? "toPayPalAccount"
      : "toBankAccount");
    setCurrentPaymentOption(currentPaymentOption);
    setPaymentScheduleChecked(initialData.paymentSchedulingType);
    setFormState(initialData);
  }, [paymentOptions, userData, setCurrentPaymentOption, setFormState]);
  useEffect(() => {
    if (!(countries === null || countries === void 0 ? void 0 : countries.length))
      return;
    if (countrySearch.trim() === "") {
      setFilteredCountries(countries || []);
    }
    else {
      setFilteredCountries(countries.filter((c) => c.displayName.toLowerCase().includes(countrySearch.toLowerCase())) || []);
    }
  }, [countrySearch, countries]);
  const updateBankCountry = (bankCountry) => {
    const currentPaymentOption = paymentOptions === null || paymentOptions === void 0 ? void 0 : paymentOptions.find((paymentOption) => {
      if (paymentOption.countryCode === bankCountry)
        return true;
      return false;
    });
    setFormState((p) => ({ ...p, bankCountry }));
    setCurrentPaymentOption(currentPaymentOption);
  };
  const runMutation = async (formData, token) => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j;
    setLoading(true);
    try {
      if (!currentPaymentOption)
        throw new Error("No currentPaymentOption");
      const body = {
        user: {
          id: user.id,
          accountId: user.accountId,
        },
        ...formData,
        paymentMethod: getPaymentMethod(currentPaymentOption),
        paymentSchedulingType: paymentScheduleChecked,
      };
      let response = null;
      let success = null;
      let validationErrors = null;
      // Call difference mutations based on whether the user is updating
      // the info for setting it for the first time
      if (isPartner) {
        if (!token)
          return; // Require token for this mutation
        response = await updateWithdrawalSettings({
          updateImpactPublisherWithdrawalSettingsInput: {
            ...body,
            accessKey: token,
          },
        });
        success = (_b = (_a = response) === null || _a === void 0 ? void 0 : _a.updateImpactPublisherWithdrawalSettings) === null || _b === void 0 ? void 0 : _b.success;
        validationErrors = (_d = (_c = response) === null || _c === void 0 ? void 0 : _c.updateImpactPublisherWithdrawalSettings) === null || _d === void 0 ? void 0 : _d.validationErrors;
      }
      else {
        response = await saveWithdrawalSettings({
          setImpactPublisherWithdrawalSettingsInput: {
            ...body,
          },
        });
        success = (_f = (_e = response) === null || _e === void 0 ? void 0 : _e.setImpactPublisherWithdrawalSettings) === null || _f === void 0 ? void 0 : _f.success;
        validationErrors = (_h = (_g = response) === null || _g === void 0 ? void 0 : _g.setImpactPublisherWithdrawalSettings) === null || _h === void 0 ? void 0 : _h.validationErrors;
      }
      if (!response || ((_j = response) === null || _j === void 0 ? void 0 : _j.message)) {
        throw new Error();
      }
      else if (!success) {
        console.error("Validation failed: ", validationErrors);
        const mappedValidationErrors = validationErrors === null || validationErrors === void 0 ? void 0 : validationErrors.reduce((agg, error) => {
          return {
            ...agg,
            [error.field]: {
              type: "invalid",
            },
          };
        }, {});
        setErrors({
          inputErrors: { ...mappedValidationErrors },
          general: true,
        });
        return;
      }
      // Fire form change event
      window.dispatchEvent(new Event(TAX_FORM_UPDATED_EVENT_KEY));
      await refetch();
      setStep("/dashboard");
    }
    catch (e) {
      console.error(e);
      setErrors({ general: true });
    }
    finally {
      setLoading(false);
    }
  };
  const onSubmit = async (event) => {
    let formData = {};
    let validationErrors = {};
    const controls = event.target.getFormControls();
    controls.forEach((control) => {
      if (!control.name || !control.id)
        return;
      const key = control.name;
      const value = control.value;
      JSONPointer.set(formData, key, value);
      if (control.required && !value) {
        JSONPointer.set(validationErrors, key, { type: "required" });
      }
    });
    setErrors({ inputErrors: validationErrors });
    if (Object.keys(validationErrors).length) {
      setShowModal(false);
      return;
    }
    let token = undefined;
    if (isPartner) {
      setShowModal(false);
      setShowVerification(true);
      token = await new Promise((res) => {
        const cb = (e) => {
          e.stopPropagation();
          host.removeEventListener(VERIFICATION_EVENT_KEY, cb);
          res(e.detail.token);
        };
        host.addEventListener(VERIFICATION_EVENT_KEY, cb);
      });
      setShowVerification(false);
    }
    await runMutation(formData, token);
    setShowModal(false);
    window.location.hash = "";
  };
  const onVerification = async (token) => {
    host.dispatchEvent(new CustomEvent(VERIFICATION_EVENT_KEY, {
      detail: { token },
      bubbles: false,
    }));
  };
  function setPaymentMethodChecked(paymentMethod) {
    _setPaymentMethodChecked(paymentMethod);
    if (paymentMethod === "toPayPalAccount") {
      const currentPaymentOption = paymentOptions === null || paymentOptions === void 0 ? void 0 : paymentOptions.find((paymentOption) => {
        if (paymentOption.defaultFinancePaymentMethodId === 7)
          return true;
        return false;
      });
      setCurrentPaymentOption(currentPaymentOption);
    }
    else if (paymentMethod === "toBankAccount") {
      const currentPaymentOption = paymentOptions === null || paymentOptions === void 0 ? void 0 : paymentOptions.find((paymentOption) => paymentOption.countryCode === formState.bankCountry);
      setCurrentPaymentOption(currentPaymentOption);
    }
  }
  return {
    text: props.getTextProps(),
    callbacks: {
      onSubmit,
      setBankCountry: updateBankCountry,
      setPaymentMethodChecked,
      setPaymentScheduleChecked,
      onBack: () => {
        // return to dashboard
        if (window.location.hash) {
          window.location.hash = "";
        }
        else {
          setStep("/dashboard");
        }
      },
      setCountrySearch,
      onVerification,
      onVerificationHide: () => onVerification(null),
      onModalClose: () => setShowModal(false),
      onModalOpen: () => setShowModal(true),
    },
    states: {
      showVerification,
      step: step === null || step === void 0 ? void 0 : step.replace("/", ""),
      hideSteps: !!context.hideSteps,
      saveDisabled: !paymentMethodChecked || !paymentScheduleChecked,
      locale,
      isPartner,
      feeCap,
      paymentMethodFeeLabel,
      disabled: loading,
      hideBackButton: !context.overrideBackStep,
      loading: !paymentOptions,
      saveLoading: loading,
      hideBanking: paymentMethodChecked !== "toBankAccount" || !paymentMethodChecked,
      hidePayPal: paymentMethodChecked !== "toPayPalAccount" || !paymentMethodChecked,
      loadingError: !!(userError === null || userError === void 0 ? void 0 : userError.message) || !!(paymentOptionsError === null || paymentOptionsError === void 0 ? void 0 : paymentOptionsError.message),
      formState: {
        ...formState,
        paymentMethodChecked,
        paymentScheduleChecked,
        errors,
      },
      currentPaymentOption,
      bitset: (currentPaymentOption === null || currentPaymentOption === void 0 ? void 0 : currentPaymentOption.withdrawalSettingId) || 0,
      currency,
      thresholds: ((_h = currentPaymentOption === null || currentPaymentOption === void 0 ? void 0 : currentPaymentOption.thresholdOptions) === null || _h === void 0 ? void 0 : _h.split(",")) || [],
      countries: filteredCountries,
      allCountries: countries,
      hasPayPal,
      bankCountry: formState.bankCountry,
      countrySearch,
      email: (_j = userData === null || userData === void 0 ? void 0 : userData.user) === null || _j === void 0 ? void 0 : _j.email,
      showModal,
    },
    refs: {
      formRef,
    },
  };
}
