import React, { useEffect, useState, memo, useCallback, useRef } from "react";
import useForceUpdate from "use-force-update";
import { Controller, PID, SID } from "@tingwu/core";
import { ParagraphContent } from "../paragraphContent";
import { ScrollToBottom } from "../scrollToBottom";
import { Empty } from "../empty";
import { Wrapper, FixParagraphList, ParagraphContentBox } from "./styled";
import { generateTranscriptionController, useTranscriptionHooks } from "../../controller";
import { useSyncEffect } from "@tingwu/common";
import { useScrollView } from "../../scrollView";
import { QAModelType, UserChangeActiveQna, useSphereState } from "@tingwu/sphere";
import {
  isRenderUnfixParagraphState,
  isRoughlyTranscripingState,
} from "../../model/controllerState";
import { useRecoilValue } from "recoil";

export interface TranscriptionContentProps {
  controller: Controller;
  isShowingLivingScrollToBottom?: boolean;
  style?: React.CSSProperties;
  className?: string;
  rootClassName?: string;
  onScrollToBottom?: () => void;
  hasExtraContent?: boolean;
  theme: any;
  shareDisabled?: boolean;
}

type TimestampMap = Record<PID, string>;

export const TranscriptionContent: React.FC<TranscriptionContentProps> = memo(props => {
  const {
    controller,
    className,
    style,
    isShowingLivingScrollToBottom,
    onScrollToBottom,
    hasExtraContent = false,
    theme,
    shareDisabled,
    rootClassName,
  } = props;

  const transController = generateTranscriptionController(controller);
  const containerRef = useRef<HTMLDivElement>(null);
  const isLivingMode = controller.getLivingMode();
  const originPids = controller.getPids();
  const displayPids = controller.getPids(true);
  const [timestampMap, setTimestampMap] = useState<TimestampMap>({});
  const forceUpdate = useForceUpdate();
  const [aiReviewPid, setAiReviewPid] = useState("");
  const { qnaController, aiAssistantController } = useTranscriptionHooks(controller, [
    "qnaController",
    "aiAssistantController",
  ]);

  const isRoughlyTranscriping = useRecoilValue(isRoughlyTranscripingState);
  const isRenderUnfixParagraph = useRecoilValue(isRenderUnfixParagraphState);

  useSyncEffect(() => {
    return controller.on("paragraphListChange", ({ maybeChangedPids }) => {
      const timestamp = String(new Date().getTime());
      if (maybeChangedPids.length > 0) {
        setTimestampMap(prevTimestampMap => {
          return maybeChangedPids.reduce<TimestampMap>(
            (result, pid) => {
              // eslint-disable-next-line no-param-reassign
              result[pid] = timestamp;
              return result;
            },
            { ...prevTimestampMap }
          );
        });
      }
      forceUpdate();
    });
  }, [controller, forceUpdate]);

  useSyncEffect(() => {
    return controller.on("paragraphFilterChange", forceUpdate);
  }, [controller, forceUpdate]);

  useSyncEffect(() => {
    return controller.on("paragraphChange", ({ pid }) => {
      const timestamp = String(new Date().getTime());
      setTimestampMap(
        Object.assign({}, timestampMap, {
          [pid]: timestamp,
        })
      );
      forceUpdate();
    });
  }, [timestampMap, controller, forceUpdate]);

  const renderBeforeMask = useCallback(() => {
    const params = { onClick: onScrollToBottom };
    const elem = transController.renderUnfixMask(params);
    if (elem) {
      return elem;
    }
    return <ScrollToBottom onClick={onScrollToBottom} />;
  }, [transController, onScrollToBottom]);

  const getRenderMaskFunc = useCallback(
    (pid?: PID) => {
      if (!isShowingLivingScrollToBottom) {
        return;
      }
      if (pid != null) {
        const paragraph = controller.getParagraph(pid);
        if (paragraph.isUnfix) {
          return renderBeforeMask;
        }
      } else if (isRoughlyTranscriping) {
        return renderBeforeMask;
      }
    },
    [isShowingLivingScrollToBottom, controller, renderBeforeMask, isRoughlyTranscriping]
  );

  const emptyText = originPids.length === 0 ? "这里空空如也～" : "没有结果，请更换筛选项";

  const unfixPid = isLivingMode ? controller.getUnfixPid() : undefined;

  useEffect(() => {
    const container = containerRef.current;
    if (!window.ResizeObserver || !container) {
      return;
    }
    //
    // User will manual import `resize-observer-polyfill` if he need.
    const resizeObserver = new ResizeObserver(entries => {
      if (entries.length === 0) {
        return;
      }
      transController.emit("contentRectChange", {
        rect: entries[0].contentRect,
      });
    });
    resizeObserver.observe(container);
    return () => {
      resizeObserver.disconnect();
    };
  }, [transController]);

  const { scrollViewPids, containerHeight, isFirstParagraphBeforeContent } = useScrollView({
    controller,
    transController,
    theme,
    rootClassName,
  });

  // 这里以displayPids为准，因为scrollViewPids可能计算较慢，导致有一帧会返回空数组
  const isShowEmpty = displayPids.length === 0;

  // TODO QA data0 init
  const [qnaQSids, setQnaQSids] = useState<SID[]>([]);
  const [qnaASids, setQnaASids] = useState<SID[]>([]);
  const [activeQnaQSids, setActiveQnaQSids] = useState<SID[]>([]);
  const [activeQnaASids, setActiveQnaASids] = useState<SID[]>([]);
  const [qParagraphIds, setQParagraphIds] = useState<string[]>([]);
  const [aParagraphIds, setAParagraphIds] = useState<string[]>([]);
  const [qnaModel, setQnaModel] = useState<QAModelType>();

  useEffect(() => {
    if (!qnaController) {
      return;
    }
    setQnaQSids(qnaController.getEffectQSids());
    setQnaASids(qnaController.getEffectASids());
    setQnaModel(qnaController.getQaModel());
    return qnaController.onStateChange(event => {
      if (event.key === "qnaList") {
        setQnaQSids(qnaController.getEffectQSids());
        setQnaASids(qnaController.getEffectASids());
      }
    });
  }, [qnaController, qnaController?.model]);

  const activeQnaIndex = useSphereState(qnaController, "activeQnaIndex");
  const displayQnaList = useSphereState(qnaController, "displayQnaList");

  useEffect(() => {
    if (activeQnaIndex == null || displayQnaList == null) {
      return;
    }

    const qna = displayQnaList[activeQnaIndex];

    setActiveQnaQSids(qna ? qna.question.sids : []);
    setActiveQnaASids(qna ? qna.answer?.sids || [] : []);
    const paragraphQIdset = new Set<string>();
    const paragraphAIdset = new Set<string>();
    const paragraphQIds: string[] = [];
    const paragraphAIds: string[] = [];
    if (qna) {
      displayQnaList.forEach(item => {
        if (item.question?.sentenceInfoOfQuestion) {
          const { sentenceInfoOfQuestion } = item.question;
          const { sentenceInfoOfAnswer } = item.answer || {};
          sentenceInfoOfQuestion.forEach(qItem => {
            paragraphQIdset.add(`${qItem.paragraphId}`);
          });
          sentenceInfoOfAnswer?.forEach(qItem => {
            paragraphAIdset.add(`${qItem.paragraphId}`);
          });
        }
      });

      if (paragraphQIdset.size > 0) {
        paragraphQIdset.forEach(value => {
          paragraphQIds.push(value);
        });
      }
      if (paragraphAIdset.size > 0) {
        paragraphAIdset.forEach(value => {
          paragraphAIds.push(value);
        });
      }

      setQParagraphIds(paragraphQIds);
      setAParagraphIds(paragraphAIds);
    } else {
      setQParagraphIds([]);
      setAParagraphIds([]);
    }
  }, [activeQnaIndex, displayQnaList]);

  useEffect(() => {
    /**
     * question 问题回顾-回溯问题
     * questionAndanswer 问答回顾-回溯答案
     * mainPoint 要点回顾-回溯问题
     */

    const reviewParagraph = (event: UserChangeActiveQna, ctrl: typeof qnaController) => {
      // TODO QA 位置
      const { model } = ctrl || {}; // TODO
      const { qna } = event;
      const sids = model !== "mainPoint" ? qna?.question.sids : qna?.answer?.sids;
      if (!sids || sids.length === 0) {
        return;
      }
      const sid = sids[0];
      // TODO QA map
      const firstWord = controller.getFirstWordBySid(Array.isArray(sid) ? sid[0] : sid);

      if (firstWord) {
        const paragraph = controller.getParagraphByWid(firstWord.wid);
        if (paragraph) {
          controller.seekToWord(firstWord);
        }
      }

      const paragraph = controller.getVisibleParagraphBySids(sids);
      if (!paragraph) {
        return;
      }
      transController.playingWordController.emit("paragraphShowUp", {
        pid: paragraph.pid,
      });
    };
    qnaController &&
      qnaController.on("userChangeActiveQna", event => reviewParagraph(event, qnaController));
  }, [controller, transController, qnaController]);

  useEffect(() => {
    if (!controller || !transController) return;
    const reviewParagraph = (event: { pid: PID }) => {
      const { pid } = event;
      transController.playingWordController.emit("paragraphShowUp", {
        pid,
      });
    };
    controller.on("meetingActiveAgendaChange", event => reviewParagraph(event));
  }, [controller, transController]);

  useEffect(() => {
    aiAssistantController &&
      aiAssistantController.on("userChangeActive", event => {
        if (/\d+/.test(String(event?.time))) {
          const [pid] = controller.getLastWordByTime(event?.time as number);
          if (pid) {
            // controller.startPlayingVoiceWord();
            setAiReviewPid(pid);
            return;
          }
        }
        setAiReviewPid("");
      });
  }, [controller, aiAssistantController]);

  return (
    <Wrapper
      className={className}
      style={style}
      ref={containerRef}
      livingMode={isLivingMode}
      isHasUnfix={isRenderUnfixParagraph}
      showPaddingTop={!isFirstParagraphBeforeContent}
    >
      {isShowEmpty && <Empty fullscreen={!hasExtraContent} message={emptyText} />}

      <FixParagraphList className="fixParagraphList" style={{ height: containerHeight }}>
        {scrollViewPids.map(({ pid, style: bstyle, getBeforeContent }) => {
          const isAnaQ = qParagraphIds.includes(pid);
          const isAnaA = aParagraphIds.includes(pid);
          return (
            <ParagraphContentBox style={bstyle} key={pid}>
              {getBeforeContent()}

              <ParagraphContent
                isUnfix={false}
                renderBeforeMask={getRenderMaskFunc(pid)}
                pid={pid}
                controller={controller}
                timestamp={timestampMap[pid]}
                qnaQSids={qnaQSids}
                qnaASids={qnaASids}
                activeQnaQSids={activeQnaQSids}
                activeQnaASids={activeQnaASids}
                isAnaQ={isAnaQ && !isAnaA}
                isAnaQa={isAnaQ && isAnaA}
                qnaModel={qnaModel}
                aiReviewPid={aiReviewPid}
                shareDisabled={shareDisabled}
                qaController={qnaController}
              />
            </ParagraphContentBox>
          );
        })}
      </FixParagraphList>

      {isRenderUnfixParagraph && (
        <ParagraphContent
          isUnfix
          renderBeforeMask={getRenderMaskFunc(unfixPid)}
          pid={unfixPid}
          controller={controller}
          timestamp={unfixPid ? timestampMap[unfixPid] : undefined}
          /** 未声明 */
          // selections={unfixFoundResult?.origin}
          // translateSelections={unfixFoundResult?.translate}
          shareDisabled={shareDisabled}
        />
      )}
    </Wrapper>
  );
});
