import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";

import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";

import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";

import { insertMyInfoCheckoutOrder } from "../../../actions/checkoutActions";
import { setHidePopup, setShowPopup } from "../../../actions/commonActions";
import {
  popPanel,
  pushPanel,
  resetPanels,
} from "../../../actions/panelActions";
import { getMyInfoCardPincodeCheck } from "../../../actions/pinCodeActions";
import CustomImage from "../../../components/CustomImage/CustomImage";
import TButton from "../../../components/TButton/TButton";
import TPopUp from "../../../components/TPopUp/TPopUp";
import TQRCode from "../../../components/TQRCode/TQRCode";
import * as Config from "../../../utils/Config";
import { $L, getQRCodeUrl } from "../../../utils/helperMethods";
import { sha256 } from "../../../utils/sha256";
import { SpotlightIds } from "../../../utils/SpotlightIds";
import css from "./PinCodeInput.module.less";
import { sendLogTotalRecommend } from "../../../actions/logActions";

const PinCodeContainer = SpotlightContainerDecorator("div");
const PinCodeDigitsContainer = SpotlightContainerDecorator(
  { enterTo: "default-element" },
  "div"
);

const SpottableButton = Spottable("div");

export default function PinCodeInput({
  setPlaceOrderPopup,
  setIsOrderSuccessful,
}) {
  const dispatch = useDispatch();

  const { activePopup, popupVisible } = useSelector(
    (state) => state.common.popup
  );
  const pinCodeDatas = useSelector((state) => state.pinCode.pinCodeData);
  const userNumber = useSelector(
    (state) => state.common.appStatus.loginUserData.userNumber
  );

  const addrInfo = useSelector((state) => state.checkout?.infoForCheckoutData);
  const selectedCoupons = useSelector(
    (state) => state.checkout?.selectedCoupons
  );
  const productList = useSelector(
    (state) => state.checkout?.checkoutData?.productList?.[0]
  );
  const auctProdYn = useSelector(
    (state) => state.checkout?.checkoutData?.productList?.[0].auctProdYn
  );
  const auctFinalPriceChgDt = useSelector(
    (state) =>
      state.checkout?.checkoutData?.productList?.[0].auctFinalPriceChgDt
  );
  const serverHOST = useSelector((state) => state.common.appStatus.serverHOST);
  const serverType = useSelector((state) => state.localSettings.serverType);

  const [pin, setPin] = useState(["", "", "", ""]);
  const [errorMsg, setErrorMsg] = useState("");
  const [okClicked, setOkClicked] = useState(false);

  const isMounted = useRef(true);

  const { setupPinUrl } = useMemo(() => {
    return getQRCodeUrl({ serverHOST, serverType });
  }, [serverHOST, serverType]);

  const logInfo = useMemo(() => {
    if (productList) {
      return {
        cartTpSno: `${productList?.mbrId}_${productList?.prdtId}_${productList?.prodSno}`,
        cpnSno: `${productList?.prdtCoupon[0]?.cpnCdSeq}` ?? "",
        cpnTtl: productList?.prdtCoupon[0]?.cpnTpNm ?? "",
        dcAftrPrc: productList?.priceInfo.split("|")[1],
        dcBefPrc: productList?.priceInfo.split("|")[0],
        lgCatCd: productList?.catCd ?? "",
        lgCatNm: productList?.catNm ?? "",
        patncNm: productList?.patncNm,
        patnrId: productList?.patnrId,
        prodId: productList?.prdtId,
        prodNm: productList?.prdtNm,
        prodOptSno: productList?.prdtOpt[0]?.prodOptSno ?? "",
        qty: productList?.prodQty,
        usrNo: productList?.mbrNo,
      };
    }

    return {};
  }, [productList]);

  useEffect(() => {
    if (pinCodeDatas && pinCodeDatas.retCode !== 0 && okClicked) {
      if (!isMounted.current) return;

      if (pinCodeDatas.data.pwdErrorCnt >= 3) {
        dispatch(setShowPopup(Config.ACTIVE_POPUP.setPinCodePopup));
      } else {
        setErrorMsg($L("Your entries did not match. Please try again."));
      }
    }
  }, [pinCodeDatas, dispatch, okClicked]);

  useEffect(() => {
    setOkClicked(false);
    isMounted.current = true;

    return () => {
      isMounted.current = false;
    };
  }, []);

  useEffect(() => {
    if (popupVisible && activePopup) {
      setTimeout(() => {
        Spotlight.focus("tPopupBtn1");
      }, 0);
    }
  }, [popupVisible, activePopup]);

  const handleDigitClick = useCallback(
    (digit) => {
      const newPin = [...pin];
      const nextIndex = pin.findIndex((p) => p === "");

      if (nextIndex !== -1) {
        newPin[nextIndex] = digit;
        setPin(newPin);

        if (nextIndex === 3) {
          setTimeout(() => {
            Spotlight.focus(`pincodeOKButton`);
          }, 0);
        }
      }
    },
    [pin]
  );

  const handleBackspace = useCallback(() => {
    const newPin = [...pin];
    const lastIndex = newPin.findIndex((p) => p === "");
    const index = lastIndex === -1 ? 3 : lastIndex - 1;

    if (index >= 0) {
      newPin[index] = "";
      setPin(newPin);
    }
  }, [pin]);

  const onClickBack = useCallback(() => {
    setPin(["", "", "", ""]);
    setPlaceOrderPopup(false);
  }, []);

  const onClickForgetPinCode = useCallback(() => {
    setPin(["", "", "", ""]);
    dispatch(
      sendLogTotalRecommend({
        buttonTitle: "ForgetPINcode",
        contextName: Config.LOG_CONTEXT_NAME.PINCODE,
        messageId: Config.LOG_MESSAGE_ID.PINCODE,
      })
    );
    dispatch(setShowPopup(Config.ACTIVE_POPUP.qrPopup2));
  }, [dispatch]);

  const onClickConfirm = useCallback(() => {
    const params = {
      buttonTitle: "OK",
      contextName: Config.LOG_CONTEXT_NAME.PINCODE,
      messageId: Config.LOG_MESSAGE_ID.PINCODE,
    };
    if (pin.includes("")) {
      setErrorMsg($L("Please enter a PIN CODE."));
      dispatch(sendLogTotalRecommend({ ...params, status: "false" }));
      return;
    }
    setOkClicked(true);

    const pinString = pin.join("");
    const encryptedPin = sha256(pinString);

    const handlePinCodeCheck = (response) => {
      if (response.retCode === 0) {
        const orderProductCoupontUse = Object.keys(selectedCoupons).map(
          (productId) => {
            const { prdtId, cpnSno, cpnCdSeq } = selectedCoupons[productId];

            return {
              prdtId,
              patnrId: productList.patnrId,
              prodSno: productList.prodSno,
              cpnSno,
              cpnCdSeq,
            };
          }
        );
        const regularPrice = productList?.priceInfo.split("|")[0];
        const discountPrice = productList?.priceInfo.split("|")[1];
        const discountRate = productList?.priceInfo.split("|")[4];
        dispatch(
          sendLogTotalRecommend({
            productId: productList?.prdtId,
            item: productList?.prodQty,
            price: discountRate ? discountPrice : regularPrice,
            discount: discountRate,
            coupon: orderProductCoupontUse.length > 0 ? "Y" : "N",
            contextName: Config.LOG_CONTEXT_NAME.CHECKOUT,
            messageId: Config.LOG_MESSAGE_ID.CHECKOUT_CLICK,
          })
        );
        dispatch(
          insertMyInfoCheckoutOrder(
            {
              mbrNo: userNumber,
              bilAddrSno: addrInfo?.bilAddrSno,
              dlvrAddrSno: addrInfo?.dlvrAddrSno,
              pinCd: encryptedPin,
              orderProductCoupontUse:
                orderProductCoupontUse.length > 0 ? orderProductCoupontUse : [],
              orderProductQtyInfo: [
                {
                  cntryCd: productList?.cntryCd,
                  patnrId: productList?.patnrId,
                  prodQty: productList?.prodQty,
                  prdtId: productList?.prdtId,
                  prodOptCdCval: productList?.prdtOpt?.[0]?.prodOptCdCval || "",
                },
              ],
            },
            (response) => {
              if (!isMounted.current) return;

              if (response.data.retCode === 0) {
                dispatch(sendLogTotalRecommend({ ...params, status: "true" }));
                setIsOrderSuccessful(true);
                setPlaceOrderPopup(false);
                dispatch(
                  pushPanel({
                    name: Config.panel_names.CONFIRM_PANEL,
                    panelInfo: {
                      orderInfo: response.data.data,
                      auctProdYn: auctProdYn,
                      auctFinalPriceChgDt: auctFinalPriceChgDt,
                      currSign: productList.currSign,
                      currSignLoc: productList.currSignLoc,
                      logInfo: logInfo,
                    },
                  })
                );
              } else {
                // TODO: 에러 처리 필요 chw
              }
            }
          )
        );
      } else {
        if (!isMounted.current) return;
        setErrorMsg($L("Your entries did not match. Please try again.")); // 핀코드 검증 단계 후 에러처리
        dispatch(sendLogTotalRecommend({ ...params, status: "false" }));
      }
    };

    dispatch(
      getMyInfoCardPincodeCheck(
        {
          mbrNo: userNumber,
          pinCd: encryptedPin,
        },
        handlePinCodeCheck
      )
    );
  }, [
    pin,
    userNumber,
    addrInfo,
    selectedCoupons,
    productList,
    isMounted,
    auctProdYn,
    auctFinalPriceChgDt,
    dispatch,
    logInfo,
    setIsOrderSuccessful,
  ]);

  const handleClickSetPinCode = useCallback(() => {
    dispatch(setShowPopup(Config.ACTIVE_POPUP.qrPopup2));
  }, [dispatch]);

  const handleCancelPopup = useCallback(() => {
    dispatch(setHidePopup());
    setTimeout(() => Spotlight.focus("initFocusDigit"), 10);
  }, [dispatch]);

  const handlePinCodeSetOkButton = useCallback(() => {
    setPin(["", "", "", ""]);
    dispatch(setHidePopup());

    setTimeout(() => Spotlight.focus("initFocusDigit"), 10);
  }, [dispatch]);

  useEffect(() => {
    Spotlight.focus("initFocusDigit");
  }, []);

  return (
    <>
      <PinCodeContainer
        spotlightId={SpotlightIds.PINCODE_CONTAINER}
        className={css.pinCodeContainer}
      >
        <div className={css.headerContainer}>
          <SpottableButton className={css.backBtn} onClick={onClickBack}>
            <div className={css.arrowBtn} />
            <span className={css.backText}>{$L("Back")}</span>
          </SpottableButton>
          <h1 className={css.pinCodeTitle}>{$L("PIN Code")}</h1>
        </div>
        <div className={css.pinCodeBoxes}>
          {pin.map((digit, index) => (
            <div
              key={index}
              className={classNames(css.pinCodeBoxWrapper, {
                [css.focused]: pin.findIndex((p) => p === "") === index,
              })}
            >
              <div className={css.pinCodeBoxBackground}></div>
              <div className={css.pinCodeContent}>{digit ? "•" : ""}</div>
            </div>
          ))}
        </div>
        <div className={css.errMsg}>{errorMsg}</div>
        <PinCodeDigitsContainer className={css.pinCodeDigits}>
          {[...Array(10).keys()].map((digit) => (
            <SpottableButton
              key={digit}
              className={css.pinCodeDigit}
              onClick={() => handleDigitClick(digit.toString())}
              spotlightId={digit === 0 ? "initFocusDigit" : null}
            >
              {digit}
            </SpottableButton>
          ))}
          <SpottableButton
            className={classNames(css.pinCodeDigit, css.deleteKey)}
            onClick={handleBackspace}
          />
        </PinCodeDigitsContainer>
        <div className={css.buttonContainer}>
          <TButton onClick={onClickForgetPinCode} className={css.cancelBtn}>
            {$L("Forget PIN code?")}
          </TButton>
          <TButton
            onClick={onClickConfirm}
            className={css.okBtn}
            spotlightId="pincodeOKButton"
          >
            {$L("OK")}
          </TButton>
        </div>
      </PinCodeContainer>

      {activePopup === Config.ACTIVE_POPUP.setPinCodePopup && (
        <TPopUp
          kind="setPinCodePopup"
          open={popupVisible}
          hasButton
          button1Text={$L("OK")}
          button2Text={$L("Cancel")}
          onClick={handleClickSetPinCode}
          onClose={handleCancelPopup}
          hasText
          text={$L(
            "The number of PIN CODE errors has been exceeded and the PIN CODE cannot be used. Would you like to set a new PIN CODE?"
          )}
        />
      )}

      {activePopup === Config.ACTIVE_POPUP.qrPopup2 && (
        <TPopUp kind="qrPopup" open={popupVisible} onClose={handleCancelPopup}>
          <div className={css.popupContainer}>
            <div className={css.header}>
              <h3>{$L("QR CODE")}</h3>
            </div>

            <div className={css.qrcodeContainer}>
              <div className={css.qrcode}>
                <TQRCode text={setupPinUrl} width="360" height="360" />
              </div>
              <h3>
                {$L(
                  "If you want to add or edit your address and payment information, please scan the QR CODE."
                )}
              </h3>
              <TButton
                className={css.popupBtn}
                onClick={handlePinCodeSetOkButton}
              >
                {$L("DONE")}
              </TButton>
            </div>
          </div>
        </TPopUp>
      )}
    </>
  );
}
