import { reactive, computed, watch, ref, unref, isRef, nextTick } from 'vue'
import useFetch from '@/hooks/useFetch'
import useMainStore from '@/store/main'
import { ExtractApiResponse } from '@/api/api'
import type { Ref } from 'vue'

export interface DataModel {
  subject?: string
  question?: number
  group?: number
}

interface Group {
  label: string
  value: number
}

type QuestionList = ExtractApiResponse<'getMainQuestionList'>[0] & {
  label: string
  value: number
}

const useOptions = (
  types: (keyof DataModel)[],
  initModel?: DataModel | Ref<DataModel>,
  autoFill = true,
  subjectEnable: boolean | null = true
) => {
  const mainStore = useMainStore()

  const userInfo = computed(() => {
    return mainStore?.myUserInfo
  })

  const isAdmin = computed(() => {
    return userInfo?.value?.role === 'ADMIN'
  })

  const isChief = computed(() => {
    return userInfo?.value?.role === 'CHIEF'
  })

  const dataModel = reactive<DataModel>(unref(initModel) || {})

  if (isRef(initModel)) {
    watch(
      initModel,
      () => {
        Object.assign(dataModel, unref(initModel))
      },
      { deep: true }
    )
  }

  const changeModelValue = <T extends keyof DataModel>(key: T) => {
    return (v: DataModel[T]) => {
      dataModel[key] = v
    }
  }

  const { fetch: getSubjectList, result: subjectResult } = useFetch('getSubjectList')

  const {
    fetch: getMainQuestionList,
    result: mainQuestionListResult,
    reset: resetQuestionFetch,
  } = useFetch('getMainQuestionList')

  const {
    fetch: getQuestionGroupList,
    result: groupListResult,
    reset: resetGroupList,
  } = useFetch('getQuestionGroupList')

  const subjectList = computed(() => {
    return (
      subjectResult.value?.result?.map((subject) => {
        return { ...subject, value: subject.code, label: `${subject.code}-${subject.name}` }
      }) || []
    )
  })

  const mainQuestionList = computed<QuestionList[]>(() => {
    return (
      mainQuestionListResult.value?.map<QuestionList>((v) => {
        return {
          ...v,
          label: v.title,
          value: v.mainNumber,
        }
      }) || []
    )
  })

  const groupList = computed<Group[]>(() => {
    const list =
      groupListResult?.value?.map((n) => {
        return {
          value: n,
          label: `第${n}组`,
        }
      }) || []
    return list?.length && (isAdmin.value || isChief.value)
      ? [{ label: '全部', value: void 0 } as unknown as Group].concat(list)
      : list
  })

  const groupListWithAll = computed(() => {
    return groupList.value
  })

  watch(
    userInfo,
    () => {
      if (!dataModel.subject && userInfo.value?.subjectCode) {
        dataModel.subject = userInfo.value.subjectCode
      }
      if (!dataModel.question && userInfo.value?.mainNumber) {
        dataModel.question = userInfo.value.mainNumber
      }

      if (!dataModel.group && userInfo.value?.markingGroupNumber && !(isAdmin.value || isChief.value)) {
        dataModel.group = userInfo.value.markingGroupNumber
      }
    },
    { immediate: true }
  )

  watch(
    () => dataModel.subject,
    () => {
      if (types.includes('question') && dataModel.subject) {
        // resetQuestionFetch()
        // resetGroupList()
        // changeModelValue('question')(void 0)
        // changeModelValue('group')(void 0)
        getMainQuestionList({ subjectCode: dataModel.subject })
      }
    },
    { immediate: true }
  )

  watch(
    [() => dataModel.question, () => dataModel.question],
    () => {
      if (types.includes('group') && dataModel.subject && dataModel.question) {
        // resetGroupList()
        // changeModelValue('group')(void 0)
        getQuestionGroupList({ subjectCode: dataModel.subject, mainNumber: dataModel.question })
      }
    },
    { immediate: true }
  )

  if (autoFill) {
    watch(
      [subjectList, userInfo],
      () => {
        if (userInfo.value?.subjectCode && !dataModel.subject) {
          changeModelValue('subject')(userInfo.value?.subjectCode)
        }
      },
      { deep: true }
    )
    watch(
      [mainQuestionList, userInfo],
      () => {
        if (userInfo.value?.mainNumber && !dataModel.question) {
          changeModelValue('question')(userInfo.value?.mainNumber)
        }
      },
      { deep: true }
    )
    watch(
      [groupList, userInfo, isAdmin, isChief],
      () => {
        if (userInfo.value?.markingGroupNumber && !dataModel.question && !(isAdmin.value || isChief.value)) {
          changeModelValue('group')(userInfo.value?.markingGroupNumber)
        }
      },
      { deep: true }
    )
  }

  const initFinish = ref<boolean>(false)

  const destroyInit = watch(
    [dataModel, isAdmin, isChief],
    () => {
      if (types.every((t) => dataModel[t] || (t === 'group' && (isAdmin.value || isChief.value)))) {
        nextTick(() => {
          initCallbacks.forEach((cb) => cb(dataModel))
          initFinish.value = true
          destroyInit()
        })
      }
    },
    { immediate: true }
  )

  const initCallbacks: ((d: DataModel) => void)[] = []

  const onOptionInit = (cb: (d?: DataModel) => void) => {
    initCallbacks.push(cb)
  }

  const forceRefresh = () => {
    getSubjectList({ pageNumber: 1, pageSize: 9999, enable: subjectEnable || void 0 })
  }

  if (types.includes('subject')) {
    forceRefresh()
  }

  return {
    subjectList,
    mainQuestionList,
    groupList,
    groupListWithAll,
    dataModel,
    initFinish,
    onOptionInit,
    changeModelValue,
    forceRefresh,
  }
}

export default useOptions
