import React, { useState, useCallback, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { AppDispatch } from "app/store";
import { useDispatch, useSelector } from "react-redux";
import styles from "../../styles/app.module.scss";
import { getTranslationID } from "../../translation";
import close from "../../assets/images/close.svg";
import {
  activateCardLicenseAsync,
  cleanupApps,
  selectIsLoading,
} from "../../features/license/licenseCardActivate/index";
import progress_activit from "../../assets/images/progress_activit.svg";

interface CardLicenseActivatePopupProps {
  onClose: () => void;
}

export const CardLicenseActivatePopup: React.FC<
  CardLicenseActivatePopupProps
> = (props) => {
  const { onClose } = props;
  const { t } = useTranslation();
  const dispatch: AppDispatch = useDispatch();
  const isLoading = useSelector(selectIsLoading);
  // 各テキストエリアの値
  const [keyNumber1, setKeyNumber1] = useState<string>("");
  const [keyNumber2, setKeyNumber2] = useState<string>("");
  const [keyNumber3, setKeyNumber3] = useState<string>("");
  const [keyNumber4, setKeyNumber4] = useState<string>("");
  const [keyNumber5, setKeyNumber5] = useState<string>("");
  // 1つのテキストエリアに入る最大文字数
  const TEXTAREASIZE = 4;
  // フォーカス操作時に使用
  const ref1 = useRef<HTMLTextAreaElement>(null);
  const ref2 = useRef<HTMLTextAreaElement>(null);
  const ref3 = useRef<HTMLTextAreaElement>(null);
  const ref4 = useRef<HTMLTextAreaElement>(null);
  const ref5 = useRef<HTMLTextAreaElement>(null);

  // ポップアップを閉じる処理
  const closePopup = useCallback(() => {
    if (isLoading) {
      return;
    }
    onClose();
  }, [isLoading, onClose]);

  // ブラウザのウィンドウが閉じられようとしている場合に発火するイベントハンドラ
  const handleBeforeUnload = (e: BeforeUnloadEvent) => {
    // isLoadingがtrueの場合は確認ダイアログを表示する
    if (isLoading) {
      e.preventDefault();
      // ChromeではreturnValueが必要
      e.returnValue = "";
    }
  };
  // コンポーネントがマウントされた時にイベントハンドラを登録する
  useEffect(() => {
    window.addEventListener("beforeunload", handleBeforeUnload);
    // コンポーネントがアンマウントされるときにイベントハンドラを解除する
    return () => {
      window.removeEventListener("beforeunload", handleBeforeUnload);
    };
  });

  useEffect(
    () => () => {
      // useEffectのreturnとしてcleanupAppsを実行することで、ポップアップのアンマウント時に初期化を行う
      dispatch(cleanupApps());
    },
    [dispatch]
  );

  const [isPushActivateButton, setIsPushActivateButton] =
    useState<boolean>(false);

  // 値を画面に分割して入れる
  const inputValueOnTextarea = (input: string, startArea: number) => {
    let roopCount = startArea;
    while (input.length !== 0 || roopCount === startArea) {
      switch (roopCount) {
        case 1:
          setKeyNumber1(input.slice(0, TEXTAREASIZE));
          input = input.substring(TEXTAREASIZE);
          break;
        case 2:
          setKeyNumber2(input.slice(0, TEXTAREASIZE));
          input = input.substring(TEXTAREASIZE);
          break;
        case 3:
          setKeyNumber3(input.slice(0, TEXTAREASIZE));
          input = input.substring(TEXTAREASIZE);
          break;
        case 4:
          setKeyNumber4(input.slice(0, TEXTAREASIZE));
          input = input.substring(TEXTAREASIZE);
          break;
        case 5:
          setKeyNumber5(input.slice(0, TEXTAREASIZE));
          input = input.substring(TEXTAREASIZE);
          break;
        default:
          // テキストエリア5つから溢れる文字は切り捨てる
          input = "";
      }
      roopCount += 1;
    }
  };

  // テキストエリア入力時
  const changeTextarea = (
    e: React.ChangeEvent<HTMLTextAreaElement>,
    areaNum: number
  ) => {
    const input = e.target.value
      .toUpperCase()
      .replace(/[^A-Z0-9]/g, "")
      .substring(0, 20);
    inputValueOnTextarea(input, areaNum);
    if (e.target.value.includes("\n")) {
      setTimeout(() => {
        onKeyDownEnter();
      }, 0);
    }
    moveTextarea(input.length, areaNum);
  };

  // テキストエリア入力時(paste仕様)
  const changeTextareaByPaste = (
    e: React.ClipboardEvent<HTMLTextAreaElement>,
    areaNum: number
  ) => {
    const input = e.clipboardData
      .getData("text")
      .toUpperCase()
      .replace(/[^A-Z0-9]/g, "")
      .substring(0, 20);
    inputValueOnTextarea(input, areaNum);
    moveFocusByPaste(input.length, areaNum);
    if (e.clipboardData.getData("text").includes("\n")) {
      setTimeout(() => {
        onKeyDownEnter();
      }, 0);
    }
    e.preventDefault();
  };

  // フォーカスを移動する
  const moveFocus = (target: string) => {
    // stateの反映を同期してから実施
    setTimeout(() => {
      const obj = document.getElementById(target);
      if (obj) {
        obj.focus();
      }
    }, 0);
  };

  // フォーカス移動判定
  const moveTextarea = (length: number, areaNum: number) => {
    if (length === TEXTAREASIZE && areaNum !== 5) {
      moveFocus(`textarea${(areaNum + 1).toString()}`);
    }
  };

  // カーソルを現在入力されている中での最後尾に移動する
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const moveCursorToLast = () => {
    if (keyNumber5) {
      moveFocus("textarea5");
    } else if (keyNumber4) {
      moveFocus("textarea4");
    } else if (keyNumber3) {
      moveFocus("textarea3");
    } else if (keyNumber2) {
      moveFocus("textarea2");
    } else {
      moveFocus("textarea1");
    }
  };

  // ペースト時のフォーカスを設定する
  const moveFocusByPaste = (length: number, areaNum: number) => {
    let targetNum = areaNum + Math.floor(length / 4);
    if (targetNum > 5) {
      targetNum = 5;
    }
    const target = `textarea${targetNum.toString()}`;
    moveFocus(target);
  };

  // キー入力時判定
  const keyDown = (
    e: React.KeyboardEvent<HTMLTextAreaElement>,
    areaNum: number
  ) => {
    if (e.key === "Enter") {
      e.preventDefault();
      onKeyDownEnter();
    } else if (e.key === "ArrowRight") {
      if (e.target.selectionStart === e.target.value.length) {
        moveFocus(`textarea${(areaNum + 1).toString()}`);
      }
    } else if (e.key === "ArrowLeft") {
      if (e.target.selectionStart === 0) {
        moveFocus(`textarea${(areaNum - 1).toString()}`);
      }
    } else if (/^[a-zA-Z0-9]$/.test(e.key)) {
      if (e.target.value.length === TEXTAREASIZE && !e.ctrlKey) {
        e.preventDefault();
      }
    } else if (/^[!-/:-@[-`{-~]$/.test(e.key)) {
      e.preventDefault();
    }
  };

  // Enterキー押下時の処理
  const onKeyDownEnter = () => {
    const button = document.getElementById("button");
    if (button) {
      button.focus();
      button.click();
    }
  };

  // activateボタン押下時
  const onActivateLicense = useCallback(async () => {
    setIsPushActivateButton(true);
    const keyNumber = `${keyNumber1}${keyNumber2}${keyNumber3}${keyNumber4}${keyNumber5}`;
    if (keyNumber.length !== 20) {
      moveCursorToLast();
      return;
    }

    // activateAPIの呼び出し
    const { meta } = await dispatch(
      activateCardLicenseAsync({ cardLicenseKey: keyNumber })
    );
    setIsPushActivateButton(false);

    if (meta.requestStatus === "fulfilled") {
      // カーソルを左端に戻す
      const inputBox = document.getElementById("textarea1");
      if (inputBox) {
        inputBox.focus();
      }
      dispatch(cleanupApps());
      setKeyNumber1("");
      setKeyNumber2("");
      setKeyNumber3("");
      setKeyNumber4("");
      setKeyNumber5("");
    } else {
      moveCursorToLast();
    }
  }, [
    keyNumber1,
    keyNumber2,
    keyNumber3,
    keyNumber4,
    keyNumber5,
    dispatch,
    moveCursorToLast,
  ]);

  // HTML
  return (
    <div className={`${styles.modal} ${styles.isShow}`}>
      <div className={styles.modalBox}>
        <p className={styles.modalTitle}>
          {t(getTranslationID("cardLicenseActivatePopupPage.label.title"))}
          <button type="button" onClick={closePopup}>
            <img src={close} className={styles.modalTitleIcon} alt="close" />
          </button>
        </p>

        <form className={styles.form}>
          <dl className={`${styles.formList} ${styles.hasbg}`}>
            <dt className={styles.formTitle} />
            <dt>
              <label htmlFor="inputBox">
                {t(
                  getTranslationID(
                    "cardLicenseActivatePopupPage.label.keyNumber"
                  )
                )}
              </label>
            </dt>
            <dd className={styles.last}>
              <textarea
                id="textarea1"
                name="key1"
                value={keyNumber1}
                className={styles.formInputKey}
                ref={ref1}
                // eslint-disable-next-line jsx-a11y/no-autofocus
                autoFocus
                onChange={(e) => {
                  // カーソル位置保存
                  const cursorPos = e.target.selectionStart;
                  changeTextarea(e, 1);
                  setTimeout(() => {
                    if (ref1.current) {
                      // 保存したカーソル位置に設定
                      ref1.current.selectionStart = cursorPos;
                      ref1.current.selectionEnd = cursorPos;
                    }
                  }, 0);
                }}
                onKeyDown={(e) => {
                  keyDown(e, 1);
                }}
                onFocus={(e) => {
                  if (ref1.current) {
                    ref1.current.selectionStart = e.target.value.length;
                    ref1.current.selectionEnd = e.target.value.length;
                  }
                }}
                onPaste={(e) => {
                  changeTextareaByPaste(e, 1);
                }}
              />
              <textarea
                id="textarea2"
                name="key2"
                value={keyNumber2}
                className={styles.formInputKey}
                ref={ref2}
                onChange={(e) => {
                  // カーソル位置保存
                  const cursorPos = e.target.selectionStart;
                  changeTextarea(e, 2);
                  setTimeout(() => {
                    if (ref2.current) {
                      // 保存したカーソル位置に設定
                      ref2.current.selectionStart = cursorPos;
                      ref2.current.selectionEnd = cursorPos;
                    }
                  }, 0);
                }}
                onKeyDown={(e) => {
                  keyDown(e, 2);
                }}
                onFocus={(e) => {
                  if (ref2.current) {
                    ref2.current.selectionStart = e.target.value.length;
                    ref2.current.selectionEnd = e.target.value.length;
                  }
                }}
                onPaste={(e) => {
                  changeTextareaByPaste(e, 2);
                }}
              />
              <textarea
                id="textarea3"
                name="key3"
                value={keyNumber3}
                className={styles.formInputKey}
                ref={ref3}
                onChange={(e) => {
                  // カーソル位置保存
                  const cursorPos = e.target.selectionStart;
                  changeTextarea(e, 3);
                  setTimeout(() => {
                    if (ref3.current) {
                      // 保存したカーソル位置に設定
                      ref3.current.selectionStart = cursorPos;
                      ref3.current.selectionEnd = cursorPos;
                    }
                  }, 0);
                }}
                onKeyDown={(e) => {
                  keyDown(e, 3);
                }}
                onFocus={(e) => {
                  if (ref3.current) {
                    ref3.current.selectionStart = e.target.value.length;
                    ref3.current.selectionEnd = e.target.value.length;
                  }
                }}
                onPaste={(e) => {
                  changeTextareaByPaste(e, 3);
                }}
              />
              <textarea
                id="textarea4"
                name="key4"
                value={keyNumber4}
                className={styles.formInputKey}
                ref={ref4}
                onChange={(e) => {
                  // カーソル位置保存
                  const cursorPos = e.target.selectionStart;
                  changeTextarea(e, 4);
                  setTimeout(() => {
                    if (ref4.current) {
                      // 保存したカーソル位置に設定
                      ref4.current.selectionStart = cursorPos;
                      ref4.current.selectionEnd = cursorPos;
                    }
                  }, 0);
                }}
                onKeyDown={(e) => {
                  keyDown(e, 4);
                }}
                onFocus={(e) => {
                  if (ref4.current) {
                    ref4.current.selectionStart = e.target.value.length;
                    ref4.current.selectionEnd = e.target.value.length;
                  }
                }}
                onPaste={(e) => {
                  changeTextareaByPaste(e, 4);
                }}
              />
              <textarea
                id="textarea5"
                name="key5"
                value={keyNumber5}
                className={styles.formInputKey}
                ref={ref5}
                onChange={(e) => {
                  // カーソル位置保存
                  const cursorPos = e.target.selectionStart;
                  changeTextarea(e, 5);
                  setTimeout(() => {
                    if (ref5.current) {
                      // 保存したカーソル位置に設定
                      ref5.current.selectionStart = cursorPos;
                      ref5.current.selectionEnd = cursorPos;
                    }
                  }, 0);
                }}
                onKeyDown={(e) => {
                  keyDown(e, 5);
                }}
                onFocus={(e) => {
                  if (ref5.current) {
                    ref5.current.selectionStart = e.target.value.length;
                    ref5.current.selectionEnd = e.target.value.length;
                  }
                }}
                onPaste={(e) => {
                  changeTextareaByPaste(e, 5);
                }}
              />
              {isPushActivateButton &&
                keyNumber1.length +
                  keyNumber2.length +
                  keyNumber3.length +
                  keyNumber4.length +
                  keyNumber5.length !==
                  20 && (
                  <span className={styles.formError}>
                    {t(
                      getTranslationID(
                        "cardLicenseActivatePopupPage.label.keyNumberIncorrectError"
                      )
                    )}
                  </span>
                )}
            </dd>
            <dd className={`${styles.full} ${styles.alignCenter}`}>
              <input
                id="button"
                type="button"
                name="submit"
                value={t(
                  getTranslationID(
                    "cardLicenseActivatePopupPage.label.activateButton"
                  )
                )}
                onClick={onActivateLicense}
                className={`${styles.formSubmit} ${styles.marginBtm1} ${
                  !isLoading ? styles.isActive : ""
                }`}
              />
              <img
                style={{ display: isLoading ? "inline" : "none" }}
                src={progress_activit}
                className={styles.icLoading}
                alt="Loading"
              />
            </dd>
          </dl>
        </form>
      </div>
    </div>
  );
};
