import produce from "immer";
import { createSpeakerChangeListener, Sentence, SID } from "@tingwujs/core";
import { SphereContext, SphereController } from "../../base";
import { QnAStates, getQnAInitState, QnaOriginData, QnA } from "./qnaState";

export interface UserChangeActiveQna {
  activeQnaIndex: number | undefined;
  qna?: QnA;
  /**
   * 遮挡物高度，如果有这个值，则滚动时候，去掉这个高度，
   * 应用：目前应用于QA回溯
   * 注意：！！！！其他地方如果用，请自测，并修改本条描述
   */
  shelterHeight?: number;
}

export interface QnAEventes {
  userChangeActiveQna: UserChangeActiveQna;
  qnaListChange: {
    state: QnAStates;
  };
}
/**
 * question 问题回顾
 * questionAndanswer 问答回顾
 * mainPoint 要点回顾
 */
export type QAModelType = "question" | "questionAndanswer" | "mainPoint" | "";
export enum QAModel {
  question = "question",
  questionAndanswer = "questionAndanswer",
  mainPoin = "mainPoint",
}

const invaildPattern = /^[\s.,\\/#!$%^&*;:[\]{}=\-_`~()（）【】《》，。‘’“”＝＋－]*$/;
export class QnAController extends SphereController<QnAStates, QnAEventes> {
  key = "qna";

  originData: QnaOriginData | undefined;

  watchSids: SID[] = [];
  model: QAModelType | "";
  unSpeakerChangeListen: (() => void) | null = null;

  // Set init
  constructor(context: SphereContext, model?: QAModelType) {
    super(context, getQnAInitState());
    this.unSpeakerChangeListen = createSpeakerChangeListener(
      context.tingwuController,
      () => {},
      () => this.updateDisplayQnaList()
    );
    this.listen();
    this.model = model || "";
  }

  // 挂载
  listen() {
    const { tingwuController } = this.context;
    tingwuController.on("modelValueChange", this.handleModelValueChange);
  }

  // 卸载
  unlisten() {
    const { tingwuController } = this.context;
    this.unSpeakerChangeListen?.();
    tingwuController.off("modelValueChange", this.handleModelValueChange);
  }

  handleModelValueChange = () => {
    this.updateDisplayQnaList();
  };

  setQaModel = (model: QAModelType) => {
    this.model = model;
  };

  getQaModel = () => {
    return this.model;
  };

  // 设置QA数据
  setOriginData(originData: QnaOriginData) {
    this.originData = originData;
    const qnaList: QnAStates["qnaList"] = [];
    const watchSids: SID[] = [];

    originData.questions.forEach(question => {
      const qQuestiontitleArray: string[] = [];
      const qanswertitleArray: string[] = [];
      let qQuestionsids: SID[] = [];
      let qAnswersids: SID[] = [];
      let foundUserId = "";
      let foundAnswerUserId = "";
      const answerUids: any[] = [];
      let isOnlyAnswer = true;
      if (this.model === QAModel.question && question.qSentences) {
        const sens = question.qSentences;
        sens.forEach(sen => {
          qQuestiontitleArray.push(sen.qText);
          qQuestionsids.push(String(sen.qSi));
          foundUserId = sen.qUI;
        });
        watchSids.push(...qQuestionsids);
      } else if (this.model !== QAModel.question && question.extensions) {
        const {
          sentenceIdsOfAnswer,
          sentenceIdsOfQuestion,
          sentenceInfoOfAnswer,
          sentenceInfoOfQuestion,
        } = question.extensions;
        qQuestiontitleArray.push(question.qQuestion);
        qanswertitleArray.push(question.qAnswer);
        qQuestionsids = sentenceIdsOfQuestion;
        qQuestionsids.forEach(q => {
          if (Array.isArray(q)) {
            watchSids.push(...q);
          } else {
            watchSids.push(q);
          }
        });
        qAnswersids = sentenceIdsOfAnswer;
        qAnswersids.forEach(a => {
          if (Array.isArray(a)) {
            watchSids.push(...a);
          } else {
            watchSids.push(a);
          }
        });

        if (sentenceInfoOfQuestion && sentenceInfoOfQuestion.length > 0) {
          foundUserId = sentenceInfoOfQuestion[0].ui;
        }

        if (sentenceInfoOfAnswer && sentenceInfoOfAnswer.length > 0) {
          foundAnswerUserId = sentenceInfoOfAnswer[0].ui;
          const answerUidSet = new Set();

          sentenceInfoOfAnswer.forEach(item => {
            answerUidSet.add(item.ui);
          });

          if (answerUidSet.size > 1) {
            isOnlyAnswer = false;
          }
          if (answerUidSet.size > 0) {
            answerUidSet.forEach(value => {
              answerUids.push(value);
            });
          }
        }
      }

      qnaList.push({
        id: question.qId,
        isVaild: true,
        question: {
          uid: foundUserId,
          title: qQuestiontitleArray.join(""),
          sids: qQuestionsids,
          sentenceInfoOfQuestion: question?.extensions?.sentenceInfoOfQuestion,
        },
        answer: {
          uid: foundAnswerUserId,
          uids: answerUids,
          title: qanswertitleArray.join(""),
          sids: qAnswersids,
          isOnly: isOnlyAnswer,
          sentenceInfoOfAnswer: question?.extensions?.sentenceInfoOfAnswer,
        },
      });
    });
    this.watchSids = watchSids;
    this.setState("qnaList", qnaList);

    this.updateDisplayQnaList();
  }

  setActiveToFirstQna() {
    const displayQnAList = this.getState("displayQnaList");
    displayQnAList.some((qna, index) => {
      if (qna.isVaild) {
        this.setActiveQnaIndex(index);
        return true;
      }
      return false;
    });
  }

  // 获取QA数据-原始
  getOriginData() {
    return this.originData;
  }
  generateQna(originQna: QnA, sentences: Sentence[]): QnA {
    const { tingwuController } = this.context;
    const { question, answer } = originQna;

    const FQSentences = sentences.filter(sentence => {
      return question.sids.indexOf(sentence.sid) > -1;
    });

    let title = "";
    if (!originQna.question.title) {
      const textArray: string[] = [];
      FQSentences.forEach(s => {
        s.wids.forEach(wid => {
          const word = tingwuController.getWord(wid);
          textArray.push(word.text);
        });
      });
      title = textArray.join("");
      if (title.match(invaildPattern)) {
        return produce(originQna, draft => {
          draft.isVaild = false;
        });
      }
    }
    const firstQuestionWid = FQSentences?.[0]?.wids?.[0] || "";
    const findQuestionParagraph = tingwuController.getParagraphByWid(firstQuestionWid);
    if (answer && this.model !== QAModel.question) {
      const AFSentences = sentences.filter(sentence => {
        return answer.sids.indexOf(sentence.sid) > -1;
      });

      let answertitle = "";
      if (!originQna.answer?.title) {
        const textAnswerArray: string[] = [];
        AFSentences.forEach(s => {
          s.wids.forEach(wid => {
            const word = tingwuController.getWord(wid);
            textAnswerArray.push(word.text);
          });
        });

        answertitle = textAnswerArray.join("");

        if (answertitle.match(invaildPattern)) {
          return produce(originQna, draft => {
            draft.isVaild = false;
          });
        }
      }
      // const firstAnswerWid = AFSentences?.[0]?.wids?.[0] || '';

      // const findAnswerParagraph = tingwuController.getParagraphByWid(firstAnswerWid);

      let firstAnswerUid: string;
      const answerUidSet = new Set();
      const answerUids: any[] = [];
      let isOnly = true;

      if (AFSentences.length > 0) {
        for (let index = 0; index < AFSentences.length; index++) {
          const answerWid = AFSentences[index].wids[0];
          const findParagraph = tingwuController.getParagraphByWid(answerWid);
          if (findParagraph) {
            answerUidSet.add(findParagraph.uid);
          }
          // if (findParagraph && findParagraph.uid && firstAnswerUid !== findParagraph.uid) {
          // isOnly = false;
          // break;
          // }
        }
        if (answerUidSet.size > 1) {
          isOnly = false;
        }

        if (answerUidSet.size > 0) {
          answerUidSet.forEach(value => {
            answerUids.push(value);
          });
          // answerUids = [...answerUidSet];
          firstAnswerUid = answerUids[0];
        }
      }

      return produce(originQna, draft => {
        draft.question.title = title || originQna.question.title;
        draft.question.uid = findQuestionParagraph?.uid || "";
        if (draft.answer && originQna.answer) {
          draft.answer.title = answertitle || originQna.answer.title;
          draft.answer.uid = firstAnswerUid || "";
          draft.answer.isOnly = isOnly;
          draft.answer.uids = answerUids;
        }
      });
    }

    return produce(originQna, draft => {
      draft.question.title = title;
      draft.question.uid = findQuestionParagraph?.uid || "";
    });
  }

  updateDisplayQnaList(prevenProduce?: boolean) {
    const qnaList = this.getState("qnaList");
    let displayQnaList = JSON.parse(JSON.stringify(qnaList));
    if (!prevenProduce) {
      const { tingwuController } = this.context;
      const sentencesMap = tingwuController.getSentencesBySids(this.watchSids);

      const sentences = Object.keys(sentencesMap).map(sid => sentencesMap[sid]);
      displayQnaList = produce(qnaList, draft => {
        draft.forEach((qna, index) => {
          draft[index] = this.generateQna(qna, sentences);
        });
      });
    }
    this.setState("displayQnaList", displayQnaList);
  }

  getQnAList() {
    return this.getState("qnaList");
  }

  getEffectQSids(): SID[] {
    const sids: SID[] = [];
    this.getState("qnaList").forEach(qna => {
      sids.push(...qna.question.sids);
    });
    return sids;
  }
  getEffectASids(): SID[] {
    const sids: SID[] = [];
    this.getState("qnaList").forEach(qna => {
      sids.push(...(qna.answer?.sids || []));
    });
    return sids;
  }
  getActiveQnaIndex() {
    return this.getState("activeQnaIndex");
  }

  // 切换选中
  setActiveQnaIndex(index: number) {
    if (index === this.getActiveQnaIndex()) return;
    if (index < 0) {
      // 取消选中
      this.setState("activeQnaIndex", -1);
    } else {
      // 选中
      const displayQnaList = this.getState("displayQnaList");
      const safeIndex = Math.max(0, Math.min(index, displayQnaList.length - 1));
      const qna = displayQnaList[safeIndex];
      // 改变样式
      this.setState("activeQnaIndex", safeIndex);
      // 改变位置
      this.emit("userChangeActiveQna", {
        activeQnaIndex: safeIndex,
        qna,
      });
    }
  }
}
