import useInInstructor from '@inject/shared/hooks/useInInstructor'
import notEmpty from '@inject/shared/utils/notEmpty'
import { reject } from 'lodash'
import { useEffect } from 'react'
import type { EmailThread } from '../fragments/EmailThread.generated'
import { useSetIsUnreadEmailThread } from '../mutations/clientonly/SetIsUnreadEmailThread.generated'
import { useGetEmailThreads } from '../queries/GetEmailThreads.generated'
import type { EmailThreadsSubscription } from '../subscriptions/EmailThreads.generated'
import { EmailThreadsSubscriptionDocument } from '../subscriptions/EmailThreads.generated'

const useEmailThreadSubscription = (
  teamId: string,
  selectedThreadId?: string
) => {
  const isInstructor = useInInstructor()

  const [setIsUnread] = useSetIsUnreadEmailThread()
  const query = useGetEmailThreads({
    variables: {
      teamId,
    },
    initialFetchPolicy: 'network-only',
    nextFetchPolicy: 'cache-and-network',
    onCompleted: data => {
      const setThreadIds = new Set<string>()
      data.emailThreads?.filter(notEmpty).forEach(emailThread => {
        // skip if in current context (if thread is already open)
        if (selectedThreadId === emailThread.id) return

        emailThread.emails.forEach(email => {
          if (!email.readReceipt && !setThreadIds.has(emailThread.id)) {
            setIsUnread({
              variables: {
                threadId: emailThread.id,
                teamId,
                isUnread: true,
              },
              onCompleted: () => setThreadIds.add(emailThread.id),
            })
          }
        })
      })
    },
  })

  const { subscribeToMore, networkStatus } = query
  useEffect(
    () =>
      subscribeToMore({
        document: EmailThreadsSubscriptionDocument,
        variables: {
          teamId,
        },
        updateQuery: (prev, { subscriptionData }) => {
          // Note: this is a hack, because Codegen implicitly typecasts subscriptionData to the parent query type, this is not desired
          const retypedData =
            subscriptionData.data as unknown as EmailThreadsSubscription
          if (!retypedData) return prev

          const newEmailThread = retypedData.emailThreads?.emailThread
          if (!newEmailThread) return prev

          // skip if in current context (if thread is already open)
          if (selectedThreadId !== newEmailThread.id) {
            setIsUnread({
              variables: {
                threadId: newEmailThread.id,
                teamId,
                isUnread: true,
              },
            })
          }

          const oldEmailThreads = prev.emailThreads || []
          const oldEmailThread = oldEmailThreads.find(
            oldThread => oldThread?.id === newEmailThread.id
          )
          if (oldEmailThread?.emails.length === newEmailThread.emails.length)
            return prev

          const newEmailThreads = reject(
            oldEmailThreads,
            (oldThread: EmailThread) => oldThread.id === newEmailThread.id
          ) as EmailThread[]
          newEmailThreads.push(newEmailThread)

          return {
            ...prev,
            emailThreads: newEmailThreads,
          }
        },
      }),
    [teamId, subscribeToMore, isInstructor, setIsUnread, selectedThreadId]
  )

  return {
    networkStatus,
    teamId,
  }
}

export default useEmailThreadSubscription
