import { useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useAuth } from "react-oidc-js";

import moment from "moment-jalaali";
import starkString from "starkstring";

import {
  usePostOtcV1PrivateOtcConvertConfirm,
  usePostOtcV1PrivateOtcConvertLimit,
  usePostOtcV1PrivateOtcConvertMarket,
  usePostOtcV1PublicOtcConvertPreview,
} from "../../services";
import { useAssets } from "../useAssets";
import { ConvertContext, ConvertProps } from "./context";

type OrderProps = {
  triggerBeforeOrder?: () => Promise<void> | void;
};

export const useConvert = ({
  type,
  onError,
  onSuccess,
  validityDurationInSecond,
}: ConvertProps) => {
  if (typeof ConvertContext.context === "undefined") {
    throw new Error("You must use this hook under the ConvertProvider.");
  }

  const { userData } = useAuth();

  const { t } = useTranslation();
  const { setValue, handleSubmit, getValues, setError, getFieldState } =
    ConvertContext.useFormContext();
  const { allAssets } = useAssets();

  useEffect(() => {
    const { fromAsset } = getValues();
    if (fromAsset === undefined) {
      const BTC = allAssets?.find(
        ({ symbol }) => symbol?.toUpperCase() === "BTC",
      );
      const symbol = BTC?.symbol ? BTC?.symbol : allAssets?.[0]?.symbol;
      setValue("fromAsset", symbol);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [allAssets]);

  const {
    mutate: confirmMarket,
    isLoading: isLoadingMarketOrder,
    error: errorMarketOrder,
    reset: resetMarketOrder,
  } = usePostOtcV1PrivateOtcConvertConfirm({
    onSuccess: (data) => {
      setValue("fromAmount", "");
      setValue("toAmount", "");
      onSuccess?.(data);
      setValue("isPreviewOpen", false);
    },
    onError: (error) => {
      onError?.(error);
    },
  });
  const {
    mutate: confirmLimit,
    isLoading: isLoadingLimitOrder,
    error: errorLimitOrder,
    reset: resetLimitOrder,
  } = usePostOtcV1PrivateOtcConvertLimit({
    onSuccess: (data) => {
      setValue("fromAmount", "");
      setValue("toAmount", "");
      onSuccess?.(data);
      setValue("isPreviewOpen", false);
    },
    onError: (error) => {
      onError?.(error);
    },
  });

  //preview orders

  const {
    data: previewItemMarket,
    reset: resetPreviewMarket,
    mutate: requestPreviewMutate,
    isLoading: isLoadingMarketPreview,
    error: errorMarketPreview,
  } = usePostOtcV1PrivateOtcConvertMarket({
    onSuccess: () => {
      setValue("isPreviewOpen", true);
    },
  });
  const {
    data: previewItemLimit,
    reset: resetPreviewLimit,
    mutate: requestPreviewMutateLimit,
    isLoading: isLoadingLimitPreview,
    error: errorLimitPreview,
  } = usePostOtcV1PublicOtcConvertPreview({
    onSuccess: () => {
      setValue("isPreviewOpen", true);
    },
  });
  const onConfirm = useCallback(
    async ({ triggerBeforeOrder }: OrderProps) => {
      await triggerBeforeOrder?.();

      const order = handleSubmit(({ limitExpireDate }) => {
        if (type === "market") {
          confirmMarket({
            queryParams: { otcConvertQuoteId: previewItemMarket?.id },
          });
        } else {
          const { fromAsset, lastChangedField, toAsset, fromAmount, price } =
            getValues();
          confirmLimit({
            requestBody: {
              expireDate:
                limitExpireDate ||
                moment().clone().add(30, "days").startOf("day").toISOString(),
              sourceQuantity:
                lastChangedField === "from"
                  ? starkString(fromAmount || 0)
                      .parseNumber()
                      .toNumber()
                  : 0,
              destinationCurrencySymbol: toAsset,
              sourceCurrencySymbol: fromAsset,
              price: Number(price),
              validityDurationInSecond,
            },
          });
        }
      });

      order();
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [previewItemLimit, previewItemMarket, type, validityDurationInSecond],
  );

  const requestPreview = useCallback(
    async () => {
      const { error: errorFrom } = getFieldState("fromAmount");
      const { error: errorTo } = getFieldState("toAmount");
      if (errorFrom || errorTo) {
        return;
      }

      const order = handleSubmit(
        ({ fromAmount, toAmount, lastChangedField, toAsset, fromAsset }) => {
          if (!fromAmount && lastChangedField === "from") {
            return setError("fromAmount", { message: t("enterAmount") });
          }
          if (!toAmount && lastChangedField === "to") {
            return setError("toAmount", { message: t("enterAmount") });
          }
          if (type === "market" && !!userData) {
            requestPreviewMutate({
              requestBody: {
                validityDurationInSecond,
                sourceQuantity:
                  lastChangedField === "from"
                    ? starkString(fromAmount || 0)
                        .parseNumber()
                        .toNumber()
                    : undefined,
                destinationQunatity:
                  lastChangedField === "to"
                    ? starkString(toAmount || 0)
                        .parseNumber()
                        .toNumber()
                    : undefined,
                sourceCurrencySymbol: fromAsset,
                destinationCurrencySymbol: toAsset,
              },
            });
          } else {
            requestPreviewMutateLimit({
              requestBody: {
                validityDurationInSecond,
                sourceQuantity:
                  lastChangedField === "from"
                    ? starkString(fromAmount || 0)
                        .parseNumber()
                        .toNumber()
                    : undefined,
                destinationQunatity:
                  lastChangedField === "to"
                    ? starkString(toAmount || 0)
                        .parseNumber()
                        .toNumber()
                    : undefined,
                sourceCurrencySymbol: fromAsset,
                destinationCurrencySymbol: toAsset,
              },
            });
          }
        },
      );

      order();
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [type, userData, validityDurationInSecond],
  );

  const closePreview = useCallback(() => {
    if (type === "limit") {
      resetPreviewLimit();
      resetLimitOrder();
      setValue("isPreviewOpen", false);
    } else {
      resetPreviewMarket();
      resetMarketOrder();
      setValue("isPreviewOpen", false);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [type]);

  return {
    onConfirm,
    isLoadingConfirm: isLoadingMarketOrder || isLoadingLimitOrder,
    isLoadingPreview: isLoadingMarketPreview || isLoadingLimitPreview,
    errorPreview: errorLimitPreview || errorMarketPreview,
    error: errorLimitOrder || errorMarketOrder,
    previewItem:
      type === "limit" || !userData ? previewItemLimit : previewItemMarket,
    resetPreviewApi:
      type === "limit" || !userData ? resetPreviewLimit : resetPreviewMarket,
    resetSubmitApi:
      type === "limit" || !userData ? resetLimitOrder : resetMarketOrder,
    closePreview,
    requestPreview,
  };
};
