import {computed, ref} from 'vue'
import {createEventHook, injectLocal, provideLocal} from "@vueuse/core";
import {empty} from "@/uni_modules/uv-ui-tools/libs/function/test";
import {
    commitExamineePaper,
    commitExamineeQuestion,
    scoreExamineeQuestion,
    scoreFinish
} from "@/api/webApi/studentEvaluating";
import mxConst from "@/common/mxConst";
import _ from "lodash";
import {toast} from "@/uni_modules/uv-ui-tools/libs/function";

const key = Symbol('PAPER_SERVICE')

// 尽量保持只需要依靠paper/paper.questions中计算的相关API在paperService中
// 与userData计算相关的API集中的questionService中
export const useProvidePaperService = function (paperDataRef, overrideService = {}) {
    const paper = paperDataRef
    // 因为注入服务时paper可能还没有返回，为了方便注入时的有明确的属性名参考，这里将可能有用的属性抄了一遍。
    const props = {
        paperName: computed(() => paper.value?.name),
        allowAnswer: computed(() => paper.value?.allowAnswer),
        allowScore: computed(() => paper.value?.allowScore),
        questions: computed(() => paper.value?.questions || []),
        examineeId: computed(() => paper.value?.examineeId),
        examineeType: computed(() => paper.value?.examineeType),
        scoringType: computed(() => paper.value?.scoringType),
        remaining: computed(() => paper.value?.remaining),

        // for fast query by questionId
        questionsMap: computed(() => _.keyBy(props.questions.value, 'questionId'))
    }

    // 事件定义
    const events = {
        questionChange: createEventHook(), // display question change(index change)
        answerChange: createEventHook(), // user answered question
        answerComplete: createEventHook(), // all questions are answered
        scoreChange: createEventHook(), // user scored question
        scoreComplete: createEventHook(), // all questions are scored
        continueNext: createEventHook() // continue next paper
    }

    // data & service define
    const index = ref(0)
    const loading = ref(false)
    const current = computed(() => props.questions.value[index.value] || {})
    const hasNext = computed(() => index.value < props.questions.value.length - 1)
    const hasPrev = computed(() => index.value > 0)

    // methods
    const methods = {
        reset: () => {
            paper.value = {}
            index.value = 0
            loading.value = false
        },
        isObjective: (q) => mxConst.question.isObjective(q.typeId),
        isCheckbox: (q) => mxConst.question.isCheckbox(q.typeId),
        isRadio: (q) => mxConst.question.isRadio(q.typeId),
        isAnswerCorrect: (q) => q.answers?.length && q.answer == q.answers[0].toString(),
        tryGoNext: () => {
            if (!hasNext.value) return toast('已经是最后一题了')
            index.value += 1
        },
        tryGoPrev: () => {
            if (!hasPrev.value) return toast('已经是第一题了')
            index.value -= 1
        },
        goToQuestion: (q) => {
            const idx = props.questions.value.indexOf(q)
            if (idx > -1) index.value = idx
        },
        commitQuestion: async (commits) => {
            if (empty(commits)) return
            if (loading.value) return
            try {
                loading.value = true
                const examineeId = props.examineeId.value
                const examineeType = props.examineeType.value
                const commit = {examineeId, examineeType, questions: commits}
                await commitExamineeQuestion(commit)
                await events.answerChange.trigger(commits)
            } finally {
                loading.value = false
            }
        },
        commitPaper: async () => {
            if (loading.value) return
            try {
                // uni.showLoading() // 不需要，交卷时有自定义弹窗
                loading.value = true
                const examineeId = props.examineeId.value
                const examineeType = props.examineeType.value
                const commit = {examineeId, examineeType}
                await commitExamineePaper(commit)
                await events.answerComplete.trigger()
            } finally {
                loading.value = false
                // uni.hideLoading()
            }
        },
        scoreQuestion: async (commits) => {
            if (empty(commits)) return
            if (loading.value) return
            try {
                loading.value = true
                const examineeId = props.examineeId.value
                const examineeType = props.examineeType.value
                const commit = {examineeId, examineeType, questions: commits}
                await scoreExamineeQuestion(commit)
                await events.scoreChange.trigger(commits)
            } finally {
                loading.value = false
            }
        },
        scorePaper: async () => {
            if (loading.value) return
            try {
                uni.showLoading()
                loading.value = true
                const examineeId = props.examineeId.value
                const examineeType = props.examineeType.value
                const commit = {examineeId, examineeType}
                await scoreFinish(commit)
                await events.scoreComplete.trigger()
            } finally {
                loading.value = false
                uni.hideLoading()
            }
        },
        triggerContinueNext: async () => {
            await events.continueNext.trigger()
        }
    }

    // api that should combine `props` & `methods`
    const extend = {
        isAllObjective: computed(() => {
            return props.questions.value.every(q => methods.isObjective(q))
        }),
        answerCompletedTips: computed(() => {
            const type = props.scoringType.value + ''
            const source = {
                "1": `客观题已自动计分，主观题需要手动计分`,
                "2": `此卷为老师阅卷，需要学生交卷后老师进行阅卷计分`,
                "3": `此卷为系统阅卷，提交后系统自动计分`
            }
            return source[type] || source['1']
        })
    }

    const options = {
        loading,
        paper,
        ...props,
        onAnswerChange: events.answerChange.on,
        onAnswerComplete: events.answerComplete.on,
        onScoreChange: events.scoreChange.on,
        onScoreComplete: events.scoreComplete.on,
        onContinueNext: events.continueNext.on,
        index,
        current,
        hasNext,
        hasPrev,
        ...methods,
        ...extend,
        ...overrideService
    }

    provideLocal(key, options)
    return options
}

export const useInjectPaperService = function () {
    return injectLocal(key)
}