import {
    createGroupApi,
    CreateGroupInput,
    deleteGroupApi,
    getGroupsApi,
    patchGroupApi,
    PatchGroupInput
} from '@/entity/group/api/groupApiService'
import { Group } from '@/type/template'
import {
    QueryClient,
    useMutation,
    useQuery,
    useQueryClient,
} from '@tanstack/react-query'
import { createContext, ReactNode, useContext, useMemo } from 'react'

export const queryClient = new QueryClient()

interface GroupContextType {
  groups: Group[]
  isLoading: boolean
  error: Error | null
  refetchGroups: () => void
  addGroup: (data: CreateGroupInput) => Promise<Group>
  updateGroup: (
    groupId: string,
    data: PatchGroupInput
  ) => Promise<Group>
  deleteGroup: (groupId: string) => Promise<string>
  getGroupById: (groupId: string) => Group | undefined
}

const GroupContext = createContext<GroupContextType | undefined>(undefined)

export const GroupProvider: React.FC<{ children: ReactNode }> = ({
  children,
}) => {
  const client = useQueryClient()

  const {
    data: groups = [],
    status: listStatus,
    error: errorList,
    refetch,
  } = useQuery<Group[], Error>({
    queryKey: ['groups'],
    queryFn: async () => {
      const { groups: apiList } = await getGroupsApi()
      return apiList.sort((a, b) => a.order - b.order)
    },
  })

  const createMutation = useMutation({
    mutationFn: async (group: CreateGroupInput) => {
      const { id } = await createGroupApi(group)
      // Возвращаем созданную группу, получив её с сервера
      const { groups: updatedGroups } = await getGroupsApi()
      const newGroup = updatedGroups.find(g => g.id === id)
      if (!newGroup) throw new Error('Группа не найдена после создания')
      return newGroup
    },
    onSuccess: () => {
      client.invalidateQueries({ queryKey: ['groups'] })
    },
  })

  const updateMutation = useMutation({
    mutationFn: async ({
      groupId,
      data,
    }: {
      groupId: string
      data: PatchGroupInput
    }) => {
      return await patchGroupApi(groupId, data)
    },
    onSuccess: () => {
      client.invalidateQueries({ queryKey: ['groups'] })
    },
  })

  const deleteMutation = useMutation({
    mutationFn: async (groupId: string) => {
      await deleteGroupApi(groupId)
      return groupId
    },
    onSuccess: () => {
      client.invalidateQueries({ queryKey: ['groups'] })
    },
  })

  const getGroupById = (groupId: string) =>
    groups.find(group => group.id === groupId)

  const value = useMemo(
    () => ({
      groups,
      isLoading:
        listStatus === 'pending' ||
        createMutation.status === 'pending' ||
        updateMutation.status === 'pending' ||
        deleteMutation.status === 'pending',
      error:
        (errorList as Error) ||
        (createMutation.error as Error) ||
        (updateMutation.error as Error) ||
        (deleteMutation.error as Error) ||
        null,
      refetchGroups: refetch,
      addGroup: createMutation.mutateAsync,
      updateGroup: async (groupId: string, data: PatchGroupInput) =>
        updateMutation.mutateAsync({ groupId, data }),
      deleteGroup: deleteMutation.mutateAsync,
      getGroupById,
    }),
    [
      groups,
      listStatus,
      errorList,
      createMutation,
      updateMutation,
      deleteMutation,
      refetch,
    ]
  )

  return <GroupContext.Provider value={value}>{children}</GroupContext.Provider>
}

export const useGroupContext = (): GroupContextType => {
  const context = useContext(GroupContext)
  if (!context) {
    throw new Error('useGroupContext must be used within a GroupProvider')
  }
  return context
}