import { Controller, PID, Word, OldSelection } from "@tingwu/core";
import React, { useCallback, useEffect, useRef, useMemo, useState } from "react";
import {
  generateViewedWords,
  ViewedWord,
  generateViewedWordDiff,
  isReadonlyState,
} from "../../model";
import { updateAllWords } from "../../utils";
import { getTranscriptionController } from "../../controller";
import { ParagraphTranslate, FixText, UnfixText } from "./styled";
import { getFirstRange, useSyncEffect } from "@tingwu/common";
import { useRecoilValue } from "recoil";
import { AssistantActiveType, QnAController } from "@tingwu/sphere";

interface TranslateContentProps {
  controller: Controller;
  pid?: PID;
  isUnfix: boolean;
  translateSelections?: OldSelection[];
  activeFoundSelection?: OldSelection;
  playingWord?: Word;
  showOrigin?: boolean;
  isHighlight?: boolean;
  aiReviewActive?: AssistantActiveType | null;
  qaController?: QnAController;
}

type GetTranslateViewedWordsFunc = () => [ViewedWord[], string];

const doNothing = (id: number) => id;

export const TranslateContent: React.FC<TranslateContentProps> = props => {
  const {
    controller,
    qaController,
    pid,
    isUnfix,
    translateSelections,
    activeFoundSelection,
    playingWord,
    aiReviewActive,
    showOrigin = false,
    isHighlight = false,
  } = props;

  const transController = getTranscriptionController(controller);

  const isReadonly = useRecoilValue(isReadonlyState);

  const stateRef = useRef<{
    lastActiveWord: ViewedWord | undefined;
  }>({
    lastActiveWord: undefined,
  });
  const containerRef = useRef<HTMLDivElement>(null);
  const fixedRef = useRef<HTMLDivElement>(null);
  const [updateId, setUpdateId] = useState(0);

  const getRange = (
    callback: (range: { range: Range; startOffset: number; endOffset: number }) => void,
    fallback?: () => void
    // debug?: string,
  ) => {
    if (!containerRef.current) {
      return;
    }

    const range = getFirstRange(containerRef.current);
    if (!range) {
      fallback && fallback();
      return;
    }

    callback(range);
  };

  const getFixParagraphTranslateViewWords: GetTranslateViewedWordsFunc = useCallback(() => {
    doNothing(updateId);
    if (!pid) {
      return [[], ""];
    }
    const translate = controller.getTranslate(pid);
    console.log("log----translate----pid----", pid, translate);

    if (!translate) {
      return [[], ""];
    }
    const vws = generateViewedWords(
      translate.translateResult,
      translateSelections,
      activeFoundSelection,
      playingWord,
      true
    );
    return [vws, ""];
  }, [pid, translateSelections, activeFoundSelection, playingWord, controller, updateId]);

  const getUnfixParagraphTranslateViewWords: GetTranslateViewedWordsFunc = useCallback(() => {
    doNothing(updateId);
    const { fixContentTranslate, unfixContentTranslate } = controller.getUnfixTranslate();
    const vws = generateViewedWords(
      fixContentTranslate,
      translateSelections,
      activeFoundSelection,
      playingWord,
      true
    );
    return [vws, unfixContentTranslate];
  }, [translateSelections, activeFoundSelection, playingWord, controller, updateId]);

  const [viewedWords, extraContent] = useMemo(() => {
    return isUnfix ? getUnfixParagraphTranslateViewWords() : getFixParagraphTranslateViewWords();
  }, [isUnfix, getFixParagraphTranslateViewWords, getUnfixParagraphTranslateViewWords]);

  useEffect(() => {
    const { length } = viewedWords;
    if (!pid || length === 0) {
      return;
    }
    viewedWords.some((viewedWord, index) => {
      if (viewedWord.searchedOffsets) {
        const found = viewedWord.searchedOffsets.find(offset => offset.isActive);
        if (found) {
          const { lastActiveWord } = stateRef.current || {};
          if (!lastActiveWord || lastActiveWord.wid !== viewedWord.wid) {
            stateRef.current.lastActiveWord = viewedWord;
            transController.emitAsync("onDisplayWordShowUp", {
              pid,
              word: viewedWord,
            });
          }
          return true;
        }
      }
      if (index === length - 1) {
        stateRef.current.lastActiveWord = undefined;
      }
      return false;
    });
  }, [viewedWords, pid, transController]);

  const allContent = useMemo(() => {
    return viewedWords.map(word => word.text).join("") + extraContent;
  }, [viewedWords, extraContent]);

  const isEmptyContent = viewedWords.length === 0 && !extraContent;

  const viewedWordDiff = useMemo(() => {
    return generateViewedWordDiff();
  }, []);

  useEffect(() => {
    if (!fixedRef.current || isEmptyContent) {
      return;
    }
    updateAllWords(fixedRef.current, viewedWords);
  }, [viewedWords, isEmptyContent, viewedWordDiff]);

  useSyncEffect(() => {
    return controller.on("fixParagraphTranslateChange", ({ pid: _pid }) => {
      if (_pid === pid) {
        setUpdateId(prev => prev + 1);
      }
    });
  }, [controller, pid]);

  useSyncEffect(() => {
    if (!isUnfix) {
      return;
    }
    return controller.on("unfixParagraphTranslateChange", () => {
      setUpdateId(prev => prev + 1);
    });
  }, [controller, isUnfix]);

  const handleMouseUp = useCallback(() => {}, []);

  const preventDefault = useCallback(
    (event: React.ClipboardEvent | React.FocusEvent | React.DragEvent) => {
      event.preventDefault();
    },
    []
  );

  const handleComposition = useCallback((event: React.CompositionEvent<HTMLDivElement>) => {
    event.preventDefault();
    containerRef.current?.blur();
  }, []);

  const handleKeyDown = useCallback((event: React.KeyboardEvent) => {
    if (!event.metaKey && !event.ctrlKey) {
      event.preventDefault();
    }
  }, []);

  const handleInput = useCallback((event: React.SyntheticEvent<HTMLDivElement, InputEvent>) => {
    event.preventDefault();
  }, []);

  const handleMouseDown = useCallback(() => {
    qaController?.setActiveQnaIndex(-1);
  }, [qaController]);

  const handleSelect = useCallback(
    (event: React.SyntheticEvent<HTMLDivElement>) => {
      const { clientX, clientY, type } = event.nativeEvent as MouseEvent;

      if (!transController.getIsShowTranslatePopup()) {
        return;
      }

      getRange(
        ({ startOffset, endOffset, range }) => {
          if (startOffset !== endOffset) {
            const rangeRect = range.getBoundingClientRect();
            if (type === "mouseup") {
              let sid = "";
              let offset = 0;
              for (let i = 0; i < viewedWords.length; i++) {
                offset += viewedWords[i].text.length;
                if (offset > startOffset) {
                  sid = viewedWords[i].sentenceId;
                  break;
                }
              }

              // setTimeout(() => {
              //   transController.emit('onTranslateMenuShowUp', {
              //     clientX,
              //     clientY,
              //     rangeRect,
              //     isUnfix,
              //     pid,
              //     sid,
              //     startOffset,
              //     endOffset,
              //     content: allContent,
              //   });
              // }, 100);
            }
          } else {
            transController.emit("onTranslateMenuHideOff", {});
          }
        },
        () => {}
      );
    },
    [pid, transController, isUnfix, allContent]
  );

  const handleBlur = useCallback(() => {
    transController.emit("onTranslateMenuHideOff", {});
  }, [transController]);

  if (isEmptyContent) {
    return null;
  }

  return (
    <ParagraphTranslate
      className={`${!props.showOrigin ? "tingwu2_paragraphTranslate_showOrigin" : "tingwu2_paragraphTranslate"}`}
      contentEditable={!isUnfix && !isReadonly}
      onMouseDown={handleMouseDown}
      onMouseUp={handleMouseUp}
      onFocus={preventDefault}
      onBlur={handleBlur}
      onInput={handleInput}
      onCompositionStart={handleComposition}
      onCompositionEnd={handleComposition}
      onCut={preventDefault}
      onPaste={preventDefault}
      onDrop={preventDefault}
      onKeyDown={handleKeyDown}
      onSelect={handleSelect}
      showOrigin={showOrigin}
      isHighlight={isHighlight}
      isUnfix={isUnfix}
      spellCheck={false}
      aiReviewActive={aiReviewActive}
      ref={containerRef}
    >
      <FixText isHighlight={isHighlight} isUnfix={isUnfix} ref={fixedRef} />
      {extraContent && <UnfixText>{extraContent}</UnfixText>}
    </ParagraphTranslate>
  );
};
