"use client";

import { motion, AnimatePresence } from "framer-motion";
import { useDispatch, useSelector } from "react-redux";
import {
  hideModalOnIndex,
  resetNotificationOnIndex,
  selectModal,
  setPromisedDataOnIndex,
} from "@/utils/store/features/ui/modal.slice";
import styles from "@/components/administrator/Modal/modal.module.css";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { isPromise } from "@/app/library/library";
import Loader from "@/components/web/Loader/loader";

import { IoCloseOutline } from "react-icons/io5";

const CreateModal = ({ modalConfig, index, modal }) => {
  const dispatch = useDispatch();
  const bodyContainer = useRef(null);
  const BodyComponent = modalConfig?.component;
  const [loading, setLoading] = useState(false);
  const [promisedData, setPromisedData] = useState({});

  const handleKeyDown = useCallback(
    (event) => {
      if (!modalConfig?.onKeyDown && modalConfig?.onKeyDown !== undefined)
        return;
      if (["INPUT", "TEXTAREA"].includes(event.target.tagName)) return;

      return [
        {
          key: ["Escape"],
          call: () => {
            if (
              modalConfig?.close?.action &&
              typeof modalConfig?.close?.action === "function"
            )
              modalConfig.close.action(modal[index]?.results);
            dispatch(hideModalOnIndex(index));
          },
        },
        {
          key: ["Enter"],
          call: () => {
            event.stopPropagation();
            if (modalConfig?.acceptDisabled && !modalConfig?.accept) return;

            const bodyElement = bodyContainer.current;
            const actionPromise = isPromise(modalConfig.accept.action);
            setLoading(true);

            if (actionPromise) {
              return modalConfig.accept
                .action(bodyElement, modalConfig?.data, promisedData)
                .then((data) => {
                  if (data) dispatch(hideModalOnIndex(index));
                })
                .catch((error) => {
                  console.log(error);
                  setLoading(false);
                });
            }

            try {
              const result = modalConfig.accept.action(
                bodyElement,
                modalConfig?.data,
                promisedData
              );
              if (result) dispatch(hideModalOnIndex(index));
            } catch (error) {
              setLoading(false);
              console.log(error);
            }
          },
        },
      ]
        .find((item) => item.key.includes(event.key))
        ?.call();
    },
    [dispatch, index, modalConfig, promisedData, modal]
  );

  const handleClose = useCallback(() => {
    if (
      modalConfig?.close?.action &&
      typeof modalConfig?.close?.action === "function"
    )
      modalConfig.close.action(modal[index]?.results);
    dispatch(hideModalOnIndex(index));
  }, [dispatch, index, modalConfig, modal]);

  useEffect(() => {
    if (
      modalConfig?.promiseFunc &&
      typeof modalConfig?.promiseFunc === "function"
    ) {
      const isPromiseFunc = isPromise(modalConfig.promiseFunc);

      if (isPromiseFunc) {
        const execute = async () => {
          const data = await modalConfig.promiseFunc(index);
          dispatch(setPromisedDataOnIndex({ index, data }));
        };

        execute();
      } else {
        const data = modalConfig.promiseFunc(index);
        dispatch(setPromisedDataOnIndex({ index, data }));
      }
    }
  }, [modalConfig?.promiseFunc, dispatch, index, modalConfig]);

  useEffect(() => {
    if (!modalConfig?.notification || !modalConfig?.notification?.status)
      return;

    setTimeout(() => {
      dispatch(resetNotificationOnIndex({ index }));
    }, modalConfig?.notification?.duration || 2000);
  }, [modalConfig, dispatch, index]);

  useEffect(() => {
    const promisedData = modal[index]?.promisedData;
    if (promisedData) setPromisedData(promisedData);
  }, [modal, index]);

  useEffect(() => {
    document.addEventListener("keydown", handleKeyDown);
    return () => {
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [dispatch, index, modalConfig, promisedData, handleKeyDown]);

  return (
    <>
      <AnimatePresence>
        {modalConfig?.status && (
          <motion.div
            initial={{ opacity: 0, scale: 0.5 }}
            animate={{ opacity: 1, scale: 1 }}
            transition={{
              duration: 0.3,
              delay: 0.2,
              ease: [0, 0.71, 0.2, 1.01],
            }}
            exit={{ opacity: 0, scale: 0.5 }}
            style={{
              zIndex: index + 1,
              ...(modalConfig?.modalStyle ? modalConfig.modalStyle : {}),
            }}
            className={styles.modal_window}>
            <AnimatePresence>
              {modalConfig?.notification?.status && (
                <motion.div
                  initial={{ opacity: 0, scale: 0.5 }}
                  exit={{ opacity: 0, scale: 0.5 }}
                  animate={{ opacity: 1, scale: 1 }}
                  transition={{
                    duration: 0.8,
                    ease: [0, 0.71, 0.2, 1.01],
                  }}
                  className={styles.modal_notification}>
                  {modalConfig.notification.message}
                </motion.div>
              )}
            </AnimatePresence>
            {!modalConfig?.cannotClose && (
              <div
                className={styles.modal_close}
                onClick={(e) => handleClose()}>
                <IoCloseOutline />
              </div>
            )}
            <div
              className={styles.modal_body}
              style={{
                ...(modalConfig?.bodyStyle ? modalConfig.bodyStyle : {}),
              }}
              ref={bodyContainer}
              onKeyDown={handleKeyDown}>
              {modalConfig?.component && (
                <>
                  <BodyComponent
                    data={modalConfig?.data}
                    config={modalConfig}
                    action={{
                      close: handleClose,
                    }}
                  />
                </>
              )}
            </div>
            {!!modalConfig?.buttonShow && (
              <div className={styles.modal_footer}>
                {loading && (
                  <Loader
                    style={{ marginRight: "10px" }}
                    width={20}
                  />
                )}
                <button
                  className={styles.close}
                  onClick={(e) => handleClose()}>
                  {modalConfig.close?.text ? modalConfig.close.text : "Close"}
                </button>
                {modalConfig.accept?.text && (
                  <button
                    className={styles.accept}
                    disabled={modalConfig?.acceptDisabled}
                    onClick={(e) => {
                      const bodyElement = bodyContainer.current;
                      const actionPromise = isPromise(
                        modalConfig.accept.action
                      );
                      setLoading(true);

                      if (actionPromise) {
                        return modalConfig.accept
                          .action(
                            bodyElement,
                            modalConfig?.data,
                            promisedData,
                            modal[index]?.results
                          )
                          .then((data) => {
                            if (data) dispatch(hideModalOnIndex(index));
                          })
                          .catch((error) => {
                            setLoading(false);
                            // console.log(error);
                          });
                      }

                      try {
                        const result = modalConfig.accept.action(
                          bodyElement,
                          modalConfig?.data,
                          promisedData,
                          modal[index]?.results
                        );
                        if (result) dispatch(hideModalOnIndex(index));
                      } catch (error) {
                        // console.log(error);
                        setLoading(false);
                      }
                    }}>
                    {modalConfig.accept.text}
                  </button>
                )}
              </div>
            )}
          </motion.div>
        )}
      </AnimatePresence>
    </>
  );
};

const Modal = () => {
  const dispatch = useDispatch();
  const modalData = useSelector(selectModal);
  const lastIndex = useMemo(() => modalData.length - 1, [modalData]);

  return (
    <>
      <AnimatePresence>
        {modalData.length && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.2 }}
            // on outside click of modal
            onClick={(e) => {
              if (e.target === e.currentTarget) {
                // execute on Exit function if exists
                const currentModal = modalData[lastIndex];

                if (currentModal?.cannotClose) return;

                if (
                  currentModal?.close?.action &&
                  typeof currentModal?.close?.action === "function"
                )
                  currentModal.close.action(currentModal?.results);

                dispatch(hideModalOnIndex(lastIndex));
              }
            }}
            className={styles.modal_container}>
            {modalData.map((item, index) => (
              <CreateModal
                key={index}
                modal={modalData}
                modalConfig={{
                  ...item,
                  data: { ...(item?.data || {}), index },
                }}
                index={index}
              />
            ))}
          </motion.div>
        )}
      </AnimatePresence>
    </>
  );
};

export default Modal;
