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

import { useDispatch } from "react-redux";

import { Job } from "@enact/core/util";
import { Panel } from "@enact/sandstone/Panels";
import Cancelable from "@enact/ui/Cancelable";

import LoadingAnimation from "../../../assets/intro/splash_03_end.webp";
import { changeAppStatus } from "../../actions/commonActions";
import CustomImage from "../../components/CustomImage/CustomImage";
import PreloadImage from "../../components/PreloadImage/PreloadImage";
import { $L } from "../../utils/helperMethods";
import css from "./LoadingPanel.module.less";

const MIN_SHOWING_TIME = { launching: 2000, wait: 1000, default: 1000 };
const MAX_SHOWING_TIME = 20000;
const MAX_SHOWING_TIME_UNLIMITED = Number.MAX_SAFE_INTEGER;
const DUMMY_DELAY = 1000;
const HIDING_TIME = 1000;

const CancelablePanel = Cancelable(
  { modal: true, onCancel: "handleCancel" },
  Panel
);

let minShowingTimeJob, hidingJob, maxShowingTimeJob;

export default function LoadingPanel({ showLoadingPanel, ...rest }) {
  const dispatch = useDispatch();
  const [showingStatus, setShowingStatus] = useState({
    showing: true,
    hiding: false,
  });
  const [loadingSign, setLoadingSign] = useState("");
  const [loadingType, setLoadingType] = useState("wait");
  const [loadingImage, setLoadingImage] = useState("");
  const [readyToAni, setReadyToAni] = useState(false);
  const [readyToHide, setReadyToHide] = useState(false);

  useEffect(() => {
    return () => {
      if (minShowingTimeJob) minShowingTimeJob.stop();
      if (hidingJob) hidingJob.stop();
      if (maxShowingTimeJob) maxShowingTimeJob.stop();
    };
  }, []);

  useEffect(() => {
    if (readyToHide && !showLoadingPanel.show) {
      setTimeout(() => {
        setShowingStatus({ showing: false, hiding: true });
      }, DUMMY_DELAY);
    }
  }, [readyToHide, showLoadingPanel]);

  useEffect(() => {
    if (!showingStatus.showing) {
      if (showingStatus.hiding) {
        if (!hidingJob) {
          hidingJob = new Job(() => {
            setShowingStatus({ showing: false, hiding: false });
          }, HIDING_TIME);
        }
        hidingJob.start();
      } else {
        setReadyToHide(false);
        setReadyToAni(false);
        minShowingTimeJob && minShowingTimeJob.stop();
        hidingJob && hidingJob.stop();
        maxShowingTimeJob && maxShowingTimeJob.stop();
        dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
      }
    }
  }, [showingStatus]);

  useEffect(() => {
    if (showLoadingPanel.show) {
      if (!maxShowingTimeJob) {
        maxShowingTimeJob = new Job(
          () => {
            setShowingStatus({ showing: false, hiding: true });
          },
          showLoadingPanel.type === "wait"
            ? MAX_SHOWING_TIME_UNLIMITED
            : MAX_SHOWING_TIME
        );
      }

      maxShowingTimeJob.start();

      setShowingStatus({ showing: true, hiding: false });

      let signText = "",
        img = "";

      switch (showLoadingPanel.type) {
        case "launching": {
          signText = $L("Loading");
          img = LoadingAnimation;
          break;
        }

        case "wait": {
          signText = $L("Please wait");
          img = LoadingAnimation;
          break;
        }
      }

      setLoadingSign(signText);
      setLoadingImage(img);
      setLoadingType(showLoadingPanel.type);
    }
  }, [showLoadingPanel]);

  const handleCancel = useCallback((e) => {
    if (e) e.stopPropagation();
  }, []);

  const onPreImageLoadComplete = useCallback(() => {
    setReadyToAni(true);

    if (minShowingTimeJob) {
      minShowingTimeJob.stop();
    }

    let minTime = MIN_SHOWING_TIME[loadingType];

    if (!minTime) {
      minTime = MIN_SHOWING_TIME.default;
    }

    minShowingTimeJob = new Job(() => {
      setReadyToHide(true);
    }, minTime);

    if (showingStatus.showing) {
      minShowingTimeJob.start();
    }
  }, [showingStatus, loadingType]);

  const renderImages = useCallback(() => {
    switch (loadingType) {
      case "launching":
        return (
          <CustomImage
            className={css.fullpageImage}
            src={loadingImage}
          ></CustomImage>
        );

      case "wait":
        return (
          <section className={css.wait}>
            <p>LOADING...</p>
          </section>
        );

      default:
        return null;
    }
  }, [loadingType]);

  const hidingStyle = showingStatus.hiding
    ? { transition: "opacity " + HIDING_TIME + "ms ease", opacity: 0 }
    : {};

  if (showingStatus.showing || showingStatus.hiding) {
    return (
      <CancelablePanel
        {...rest}
        className={css.panel}
        style={hidingStyle}
        handleCancel={handleCancel}
      >
        <PreloadImage
          preloadImages={[loadingImage]}
          onLoadComplete={onPreImageLoadComplete}
        />
        {readyToAni && <div className={css.container}>{renderImages()}</div>}
      </CancelablePanel>
    );
  } else {
    return null;
  }
}

/* ---------- 

- TODO

1. 런칭 로딩 제외한 나머지 로딩 분기 처리 필요

---------- */
