import { notifier } from '@tidbcloud/uikit'
import DOMPurify from 'dompurify'
import { observer } from 'mobx-react'
import React, { Dispatch, SetStateAction, useCallback, useContext, useEffect, useState } from 'react'

import { useGetThreeArch } from 'dbaas/services/api-clients/legacy/central'
import {
  maintenanceServiceListMaintenanceTasks,
  maintenanceServiceListMaintenanceWindows
} from 'dbaas/services/api-clients/v2023/dedicated/v1beta1'
import { Dedicatedv1beta1MaintenanceTask } from 'dbaas/services/api-clients/v2023/dedicated/v1beta1/interface'
import { Dedicatedv1beta1MaintenanceWindow } from 'dbaas/services/api-clients/v2023/dedicated/v1beta1/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

type SetAction<T> = Dispatch<SetStateAction<T>>

type taskListParamsType = {
  pageSize: number
  page: number
  pageToken: string
  total: number
}

interface MaintenanceWindowContext {
  editModalOpened: boolean
  setEditModalOpened: SetAction<boolean>
  deferModalOpened: boolean
  setDeferModalOpened: SetAction<boolean>
  tableLoading: boolean
  setTableLoading: SetAction<boolean>
  taskData: Dedicatedv1beta1MaintenanceTask | null
  setTaskData: SetAction<Dedicatedv1beta1MaintenanceTask>
  maintenance: Dedicatedv1beta1MaintenanceWindow | null
  setMaintenance: SetAction<Dedicatedv1beta1MaintenanceWindow | null>
  taskList: Dedicatedv1beta1MaintenanceTask[]
  setTaskList: SetAction<Dedicatedv1beta1MaintenanceTask[]>
  getMaintenance: () => Promise<void>
  getTaskList: () => Promise<void>
  loaded: boolean
  taskListParams: taskListParamsType
  setTaskListParams: SetAction<taskListParamsType>
  isThreeArch: boolean
}

export const MaintenanceWindowContext = React.createContext<MaintenanceWindowContext | null>(null)

export const MaintenanceWindowProvider: React.FC<React.PropsWithChildren<unknown>> = observer((props) => {
  const {
    store: { tenantData, activeProject: project }
  } = useStores()

  const [editModalOpened, setEditModalOpened] = useState<boolean>(false)

  const [deferModalOpened, setDeferModalOpened] = useState<boolean>(false)

  const [tableLoading, setTableLoading] = useState<boolean>(true)

  const [taskData, setTaskData] = useState<Dedicatedv1beta1MaintenanceTask | null>(null)

  const [maintenance, setMaintenance] = useState<Dedicatedv1beta1MaintenanceWindow | null>(null)

  const [taskList, setTaskList] = useState<Dedicatedv1beta1MaintenanceTask[]>([])
  const [loaded, setLoaded] = useState(false)

  const [taskListParams, setTaskListParams] = useState<taskListParamsType>({
    pageSize: 10,
    page: 0,
    total: 0,
    pageToken: ''
  })

  const { data: threeArch, isLoading: isThreeArchLoading } = useGetThreeArch(tenantData.id, project.id, {
    query: {
      refetchOnMount: false,
      refetchOnWindowFocus: false,
      enabled: !!tenantData.id && !!project.id
    }
  })

  const getMaintenance = useCallback(async () => {
    if (isThreeArchLoading || !threeArch?.three_arch) {
      return
    }

    try {
      const resp = await maintenanceServiceListMaintenanceWindows({
        orgId: tenantData.id,
        projectId: project.id
      })
      const maintenanceWindow = resp?.maintenanceWindows?.length ? resp.maintenanceWindows[0] : null
      setMaintenance(maintenanceWindow)
    } catch (e) {
      notifier.error(<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(getErrorMessage(e, true)) }} />)
    }
  }, [tenantData.id, project.id, isThreeArchLoading])

  const getTaskList = useCallback(async () => {
    if (isThreeArchLoading) {
      return
    }

    if (!threeArch?.three_arch) {
      setTableLoading(false)
      return
    }

    setTableLoading(true)
    try {
      const resp = await maintenanceServiceListMaintenanceTasks({
        orgId: tenantData.id,
        projectId: project.id,
        pageSize: taskListParams.pageSize,
        skip: taskListParams.page * taskListParams.pageSize
      })
      setTaskList(resp?.maintenanceTasks ?? [])
      setTaskListParams({
        ...taskListParams,
        pageToken: resp?.nextPageToken ?? '',
        total: Math.ceil((resp?.totalSize ?? 0) / taskListParams.pageSize)
      })
    } catch (e) {
      notifier.error(<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(getErrorMessage(e, true)) }} />)
    } finally {
      setTableLoading(false)
      setLoaded(true)
    }
  }, [tenantData.id, project.id, taskListParams, isThreeArchLoading])

  useEffect(() => {
    getTaskList()
  }, [taskListParams.page, isThreeArchLoading])

  useEffect(() => {
    getMaintenance()
  }, [isThreeArchLoading])

  return (
    <MaintenanceWindowContext.Provider
      value={{
        editModalOpened,
        setEditModalOpened,
        deferModalOpened,
        setDeferModalOpened,
        tableLoading,
        setTableLoading,
        taskData,
        setTaskData,
        maintenance,
        setMaintenance,
        taskList,
        setTaskList,
        getMaintenance,
        getTaskList,
        loaded,
        taskListParams,
        setTaskListParams,
        isThreeArch: !!threeArch?.three_arch
      }}
    >
      {props.children}
    </MaintenanceWindowContext.Provider>
  )
})

export const useMaintenanceWindowContext = () => {
  const context = useContext(MaintenanceWindowContext)
  if (!context) {
    throw new Error('MaintenanceWindowContext is empty')
  }
  return context
}
