import {
  openExamineePaper,
  loadExamineePaper,
  commitExamineeQuestion,
  commitExamineePaper,
  scoreExamineeQuestion,
  teacherScoreExamineeQuestions,
  scoreFinish
} from '@/api/webApi/studentEvaluating.js'
import config from '@/common/mx-config.js'
import consts from '@/common/mx-const'
import { mapGetters } from 'vuex'
import { formatDuration } from '@/utils/index'
import eventMixin from './mx-question-event-mixin'
import EventBus from '@/components/EventBus'

export default {
  mixins: [eventMixin],
  props: {
    options: {
      type: Object,
      default: _ => ({
        paper: null,
        navigatorSpan: 6,
        extData: {},
        currentTab: 0,
        questionOptionsCache: {},
        committingQuestions: [],
        loading: false,
        committing: false,
        initWithAnswerOfPrevQuestion: false,
        // extra
        customScoredAction: false,
        customCommittedAction: false
      })
    }
  },
  computed: {
    ...mapGetters(['isFrontTeacher', 'isFrontStudent', 'currentUser', 'firstClassName']),
    // properties
    paper() {
      return this.options.paper
    },
    extData() {
      return this.options.extData
    },
    questionOptionsCache() {
      return this.options.questionOptionsCache
    },
    allowAnswer() {
      return this.paper.allowAnswer
    },
    allowScore() {
      return this.paper.allowScore
    },
    examineeId() {
      return this.extData.examineeId || this.paper.examineeId
    },
    examineeType() {
      return this.extData.examineeType ||
        this.paper?.examineeType ||
        consts.enum.paper.examineeType.evaluation
    },
    evaluationClassId() {
      return this.extData.evaluationClassId
    },
    studentName() {
      return this.extData.studentName || this.currentUser.nickName
    },
    studentClassName() {
      return this.extData.class || this.firstClassName
    },
    avatar() {
      return this.extData.avatar || config.avatar_default
    },
    loading() {
      return this.options.loading
    },
    committing() {
      return this.options.committing
    },
    currentTab() {
      return this.options.currentTab
    },
    committingQuestions() {
      return this.options.committingQuestions
    },

    // business data
    countdownDisplay() {
      return formatDuration(this.paper.remaining)
    },
    stateStr() {
      if (this.paper.allowAnswer || this.paper.allowScore) return ''
      return this.paper.stateStr
    },
    scoreColor() {
      return this.paper.allowAnswer ? '' : config.color.error
    },
    currentQuestion() {
      if (this.paper?.questions?.length > this.currentTab) {
        return this.paper.questions[this.currentTab]
      }
      return null
    },
    currentQuestionOptions() {
      if (!this.currentQuestion) return null
      return this.questionOptionsCache[this.currentTab]
    },
    hasPrevious() {
      return this.currentTab > 0
    },
    hasNext() {
      return this.currentTab < this.paper.questions?.length - 1
    }
  },
  methods: {
    // for shortcut
    forceBlur() {
      // Give the document focus
      if (document.activeElement) {
        document.activeElement.blur()
      }
      this.$el.focus()
    },
    loadPaper(extData, overrideOptions) {
      // set ext
      this.options.extData = extData
      if (overrideOptions) {
        Object.keys(overrideOptions).forEach(key => this.options[key] = overrideOptions[key])
      }

      // query
      let queryApi = openExamineePaper
      if (this.isFrontTeacher) queryApi = loadExamineePaper
      this.options.loading = true
      queryApi(extData).then(res => {
        this.options.currentTab = 0 // reset position
        const paper = res.data
        const autoScoreQuestions = this.eventProcessPaper(paper, this.questionOptionsCache)
        this.options.paper = paper
        this.autoScoreObjectives(autoScoreQuestions)
      }).finally(() => {
        return this.options.loading = false
      })
    },
    beforeQuestionChangeAction() {
      this.triggerAutoCommitQuestion()
    },
    goIndexAction(index) {
      if (this.currentTab != index) {
        this.triggerAutoCommitQuestion()
        this.options.currentTab = index
      }
    },
    goPreviousAction() {
      this.triggerAutoCommitQuestion()
      this.options.currentTab = this.currentTab - 1
    },
    goNextAction() {
      this.triggerAutoCommitQuestion()
      this.options.currentTab = this.currentTab + 1
    },
    goUnfinishedQuestionAction(index) {
      this.options.currentTab = index
    },
    commitQuestionAction(commit) {
      // 部分提交，断点续传
      this.committingQuestions.push(commit)
      this.commitQuestionCore()
    },
    autoScoreObjectives(scoredQuestions) {
      if (!scoredQuestions?.length) return
      // 静默提交
      const func = this.isFrontTeacher ? teacherScoreExamineeQuestions : scoreExamineeQuestion
      func({
        examineeId: this.examineeId,
        examineeType: this.examineeType,
        questions: scoredQuestions
      }).then(res => {
        // donothing
      })
    },
    paperTimeUpAction() {
      this.$once('singleCommitCompleted', _ => this.commitPaper())
      this.triggerAutoCommitQuestion()
    },
    paperSubmitAction() {
      this.$once('singleCommitCompleted', _ => {
        const unfinishedList = this.eventUnfinishedQuestions(this.paper)
        if (unfinishedList.length) {
          const msg = `检测到您还有第（${unfinishedList.map(q => q.seq)}）题没有完成，是否做完再交卷?!`
          this.$confirm(msg, '提示', {
            distinguishCancelAndClose: true,
            confirmButtonText: '继续做题',
            cancelButtonText: '确认交卷'
          }).then(() => {
            this.goUnfinishedQuestionAction(unfinishedList.first().seq - 1)
          }).catch(action => {
            if (action == 'cancel') {
              this.commitPaper()
            }
          })
        } else {
          const msg = '检测到您已完成答题'
          this.$confirm(msg, '提示', {
            confirmButtonText: '确认提交',
            cancelButtonText: '再检查一遍'
          }).then(() => this.commitPaper())
        }
      })
      this.triggerAutoCommitQuestion()
    },
    triggerAutoCommitQuestion() {
      if (!this.paper.allowAnswer) return
      const commit = this.eventBuildCommitAnswerData(this.currentQuestion)
      this.commitQuestionAction(commit)
    },
    commitQuestionCore() {
      if (this.committingQuestions.length == 0) {
        this.$emit('singleCommitCompleted')
        return
      }
      const target = this.committingQuestions[0]
      const commit = {
        examineeId: this.examineeId,
        examineeType: this.examineeType,
        questions: [{
          ...target,
          examineeType: this.examineeType
        }]
      }
      // 对比历史作答与现在提交内容是否有差异，防止切换时重复计时
      const rawQuestion = this.paper.questions.find(q => q.questionId == target.questionId)
      if (target.answer == rawQuestion.answer &&
        target.attachments.toString() == rawQuestion.attachments.toString()) {
        // 答题没有变化，不需要重复提交
        this.committingQuestions.shift()
        setTimeout(_ => this.commitQuestionCore(), 200)
        return
      }

      commitExamineeQuestion(commit)
        .then(res => {
          // 成功后可用提交属性覆盖题目属性
          this.eventHandleAnswerSubmitted(target, rawQuestion)
          this.committingQuestions.shift()
          setTimeout(_ => this.commitQuestionCore(), 200)
        }).catch(e => {
        // 失败后可尝试重复提交
        // TODO: hht 2022.1.2 这里如果一直异常了会陷入死循环
        // setTimeout(_ => this.commitQuestionCore(), 200)
      })
    },
    commitPaper() {
      if (this.committing) return
      this.options.committing = true
      const commit = {
        examineeId: this.examineeId,
        examineeType: this.examineeType,
        questions: this.paper.questions.map(q => ({
          questionId: q.questionId,
          answer: q.answer,
          attachments: q.attachments,
          duration: q.duration,
          examineeType: this.examineeType
        }))
      }

      commitExamineePaper(commit).then(res => {
        this.$alert('交卷成功').then(() => this.customCommitCompleted())
      }).finally(() => this.options.committing = false)
    },
    async scoreFinishAction() {
      const unScoredQuestions = this.eventUnScoredQuestions(this.paper)
      if (unScoredQuestions.length > 0) {
        const msg = `第${unScoredQuestions.map(q => q.seq)}题未完成评分`
        this.msgError(msg)
        this.goUnfinishedQuestionAction(unScoredQuestions.first().seq - 1)
        return
      }
      await this.$confirm('确认提交？')
      if (this.committing) return
      this.options.committing = true
      scoreFinish({
        examineeId: this.examineeId,
        examineeType: this.examineeType
      }).then(res => {
        this.$alert('阅卷完毕').then(() => this.customScoreCompleted())
      }).finally(() => this.options.committing = false)
    },
    customCommitCompleted() {
      if (this.options.customCommittedAction) {
        // NOTE: 用eventBus解耦组件层级限制
        // TODO: 这里的if-else分支不是唯一做法，也可以重写包含提交逻辑的组件，用slot装载，不知道哪种方式会更好
        this.$nextTick(() => EventBus.instance.$emit('customCommittedAction'))
      } else {
        this.$router.back()
      }
    },
    customScoreCompleted() {
      if (this.options.customScoredAction) {
        // NOTE: 用eventBus解耦组件层级限制
        // TODO: 这里的if-else分支不是唯一做法，也可以重写包含提交逻辑的组件，用slot装载，不知道哪种方式会更好
        this.$nextTick(() => EventBus.instance.$emit('customScoredAction'))
      } else {
        this.$router.back()
      }
    }
  }
}
