import React, { useEffect, useCallback, useRef } from 'react';
import { connect } from 'react-redux';
import qs from 'qs';
import ShareDefault from './ShareDefault';
import ExceptionMark from './ExceptionMark';
import ScreenContainer from './ScreenContainer';
import LoadingProgress from 'components/LoadingProgress';
import LoadingContainer from './LoadingContainer';
import NoLoadingContainer from './NoLoadingContainer';
import WatermarkCanvas from 'components/WatermarkCanvas'; // 水印
import { useSizeByDomId } from 'components/easyUse';
import { emitEvent } from 'models/interaction';
import { emitCallback } from 'models/callback';
import {
  getAllScreens,
  getScreenDetail,
  getNecessaryScreens,
  getScreenDataByPasswordAndId,
} from 'models/screen-detail';
import useLoadingPage from '../hooks/useLoadingPage';
import useControlled from '../hooks/useControlled';
import useRemoteControl from '../hooks/useRemoteControl';
import useEventTracking from '../hooks/useEventTracking';
import useHashCallback from '../hooks/useHashCallback';
import useScreenStyle from '../hooks/useScreenStyle';
import styles from './screen-detail.less';
import classNames from 'classnames';
import SharePasswordPage from 'components/SharePassword';
import message from 'components/message';
import { pathnameIsSpaceShip } from 'utils/spaceship';
import EasyvNoData from 'components/EasyvNoData';
import { isEasyvCache } from 'utils/utils';
import EasyvJurisdiction from 'components/403';
import { isOpenEasyVDebugFromUrl } from '@/utils/debug-screen';

const ScreenDetail = ({
  needPassword,
  needToken,
  userExpired,
  screenDelete,
  screentResult,
  tenantId,
  name = 'Loading',
  loading,
  config = [],
  dataAlert,
  showLoading,
  getScreenDetail,
  getAllScreens,
  getNecessaryScreens,
  emitEvent,
  emitCallback,
  rootScreens,
  screenId,
  getScreenDataByPasswordAndId,
}) => {
  const controllerRef = useRef<{
    [key: string]: AbortController;
  }>({});
  const createSignal = (id) => {
    controllerRef.current[screenId]?.abort();
    controllerRef.current?.[id]?.abort();
    const abortController = window.AbortController && new AbortController();
    controllerRef.current[id] = abortController;
    return abortController;
  };

  useEffect(() => {
    getScreenDetail(screenId).then((res) => {
      if (res) {
        const abortController = createSignal(screenId);
        getAllScreens(screenId, abortController?.signal);
      }
    });
    return () => {
      controllerRef.current = {};
    };
  }, [screenId]);

  const { loadingImageLoding, loadingPage } = useLoadingPage(screenId);

  const getId = () => {
    if (pathnameIsSpaceShip()) {
      return 'spaceship-previewContainer';
    }
    if (isOpenEasyVDebugFromUrl()) {
      return 'debug-container';
    }
  };
  const { width, height } = useSizeByDomId(getId());
  const containerStyle = useScreenStyle(config, { width, height });
  if (!isEasyvCache()) {
    // 缓存开启的时候不需要请求scoket
    const controlled = useControlled(screenId);
    useRemoteControl(controlled, emitCallback, emitEvent, rootScreens);
  }

  useHashCallback(emitCallback);
  useEventTracking({ screenId, name, tenantId });

  const handleEmitEvent = useCallback((payload) => {
    if (payload.page) {
      return;
    } else {
      emitEvent(payload);
    }
  }, []);

  const handleSumitPassword = (password) => {
    if (password) {
      getScreenDataByPasswordAndId(password, screenId, true, () => message.error('密码错误'));
    } else {
      message.error('请输入密码');
    }
  };

  const handleScreenGet = useCallback(async (id) => {
    const newAbortController = createSignal(id);
    await getNecessaryScreens(id, newAbortController?.signal);
    const abortController = createSignal(screenId);
    getAllScreens(screenId, abortController?.signal);
  }, []);

  if (loading || loadingImageLoding) {
    if (!loadingImageLoding) {
      return <LoadingProgress prepare={true} coverImg={loadingPage} />;
    } else if (loadingImageLoding && !loadingPage) {
      return null;
    }
  }

  if (screenDelete) {
    return (
      <EasyvNoData
        text={
          <>
            <p
              style={{
                color: '#fff',
                fontSize: 16,
                lineHeight: '40px',
                fontWeight: 600,
                textAlign: 'center',
              }}>
              您访问的可视化应用不存在或已被删除
            </p>
            <p style={{ color: '#B4B7C1', fontSize: 14, textAlign: 'center' }}>
              您访问的可视化应用不存在或已被删除，请确认访问的可视化应用是否存在
            </p>
          </>
        }
      />
    );
  }

  if (needPassword) {
    return <SharePasswordPage handleSumitPassword={handleSumitPassword} />;
  }

  if (needToken || screentResult === 404) {
    return <ShareDefault type={screentResult} />;
  }

  if (userExpired) {
    return <EasyvJurisdiction />;
  }

  const url = window.location.href;
  if (url.includes('?') && !loading) {
    // 七元：密码发布后，希望query不显示密码等相关信息
    const urls = url.split('?');
    const valiable = urls[0];
    const query = urls[1];
    const { timeStamp, ...param } = qs.parse(query);
    const queryString = qs.stringify(param);
    const route = queryString ? `${valiable}?${queryString}` : valiable;
    if (timeStamp) {
      // 存在密码才会处理
      window.history.pushState({}, name, route);
    }
  }

  const Container = showLoading ? LoadingContainer : NoLoadingContainer;

  return (
    <Container coverImg={loadingPage}>
      <div
        id="bigscreen-container"
        className={classNames(styles.container, {
          [styles.spaceShip]: pathnameIsSpaceShip(),
        })}
        style={containerStyle}>
        {!loading && (
          <>
            <ScreenContainer getScreenInfo={handleScreenGet} emitEvent={handleEmitEvent} />
            {dataAlert && <ExceptionMark />}
            <WatermarkCanvas width={containerStyle.width} height={containerStyle.height} />
          </>
        )}
      </div>
    </Container>
  );
};

const mapStateToProps = ({ screenDetail, screensById, panelsById, callback }) => {
  const {
    id,
    needPassword,
    screenDelete,
    loading,
    needToken,
    result: screentResult,
    userExpired,
  } = screenDetail;
  const screen = screensById[id];
  const rootScreens = Object.values(screensById)
    .filter((d: any) => !d.panelId)
    .map((d: any) => d.id);

  let name;
  let config;
  let dataAlert;
  let showLoading;
  let tenantId;

  if (screen) {
    name = screen.name;
    config = screen.config;
    dataAlert = screen.dataAlert;
    showLoading = screen.showLoading;
    tenantId = screen.tenantId;
  }
  const { callbackKeys, callbackValues } = callback;
  return {
    needPassword,
    needToken,
    screenDelete,
    loading,
    screentResult,
    callbackKeys,
    userExpired,
    callbackValues,
    tenantId,
    name,
    config,
    dataAlert,
    showLoading,
    panelsById,
    rootScreens: JSON.stringify(rootScreens),
  };
};

const mapDispatchToProps = {
  getScreenDetail,
  getAllScreens,
  getNecessaryScreens,
  emitEvent,
  emitCallback,
  getScreenDataByPasswordAndId,
};

export default connect(mapStateToProps, mapDispatchToProps)(ScreenDetail);
